Você poderia usar
system(command) Execute the operating-system command command and then return to the awk program. Return command’s exit status.
por exemplo:
awk -F: '{if(system("[ ! -d " $6 " ]") == 0) {print $1 " " $3 " " $7}}' /etc/passwd
Estou tentando gerar uma lista de usuários que possuem um conjunto de diretórios base que não existe. Parece que eu deveria ser capaz de fazer isso com o awk, mas algo está errado com a minha sintaxe.
Ele continua me dizendo "Sintaxe Inválida" no]. O que estou fazendo errado?
awk -F: '{ if(![ -d "$6"]){ print $1 " " $3 " " $7}}' /etc/passwd
O código final que provavelmente vou usar é:
awk -F: '{if(system( "[ -d " $6 " ]") == 1 && $7 != "/sbin/nologin" ) {print "The directory " $6 " does not exist for user " $1 }}' /etc/passwd
E eu tenho uma questão relacionada aqui .
Você poderia usar
system(command) Execute the operating-system command command and then return to the awk program. Return command’s exit status.
por exemplo:
awk -F: '{if(system("[ ! -d " $6 " ]") == 0) {print $1 " " $3 " " $7}}' /etc/passwd
Eu não acho que [ -d ]
seja uma coisa awk
, isso é uma coisa de shell. Eu apenas faria assim:
awk -F: '{ print $1,$3,$7}' /etc/passwd |
while read name uid shell; do
[ -d "/home/$name" ] || echo "$name $uid $shell";
done
Claro, como muito corretamente apontado por @Janis, você pode fazer tudo no shell:
while IFS=: read name x uid x x x shell rest; do
[ -d "/home/$name" ] || echo "$name $uid $shell"
done < /etc/passwd
Você pode usar getline :
awk 'BEGIN {print getline < "file" < 0 ? "not exists" : "exists"}'
É quase awk ...
perl -F: -ane 'if(!-d $F[5]){ print "$F[0] $F[2] $F[6]" }' /etc/passwd
Se você estiver realmente usando gawk
(embora você possa estar usando nawk
, ou mawk
, caso em que isso não se aplica), você pode fazer isso nativamente usando um das extensões carregáveis disponíveis desde a v4.0 . Estou usando gawk-4.1.x
(v4.0 tinha uma variação na sintaxe para carregar extensões).
O carregamento da extensão filefuncs
adiciona (entre outros) uma função stat()
:
@load "filefuncs"
BEGIN {FS=":"}
(NF==7) {
printf("user: %s %i %i\n",$1,$3,$4)
rc=stat($6,fstat)
err=ERRNO # ERRNO is a string, not an int!
if (rc<0) {
printf(" error: %s rc=%i %s\n",$6,rc,err)
} else {
if (fstat["type"]!="directory")
printf(" ENOTDIR: %s %s\n",$6,fstat["type"])
if (fstat["uid"]!=$3)
printf(" uid mismatch: %s %i!=%i\n",$6,fstat["uid"],$3)
if (fstat["gid"]!=$4)
printf(" gid mismatch: %s %i!=%i\n",$6,fstat["gid"],$4)
}
}
Veja a página filefuncs(3am)
man para detalhes sobre esta extensão.
Corra com algo como:
gawk -f testhome.awk <(getent passwd) # bash/zsh
gawk -f testhome.awk /etc/passwd
Você pode confirmar que o seu binário gawk
suporta extensões com:
BEGIN {
if (!("api_major" in PROCINFO))
printf("No extension API.\n")
else
printf("Extension API v%s.%s.\n",PROCINFO["api_major"],PROCINFO["api_minor"])
}
Além de: gawk
também vem com uma pequena função de biblioteca para ler o arquivo passwd
, você pode invocá-lo como:
gawk -i passwd.awk -- 'BEGIN { while(uu=getpwent()) {print uu;} endpwent(); }'
Eu prefiro usar getent
em sistemas Linux, pois ele suporta nsswitch.
Aqui está uma solução que
gawk
e /bin/sh
Código:
gawk -F: '{
cmd="IFS=\"\" read -r dir; [ -d \"$dir\" ]; echo $?";
print $6 |& cmd;
cmd |& getline x;
close(cmd);
if (x) print x " " $1 " " $3 " " $7
}' /etc/passwd
explicado:
IFS="" read -r dir; [ -d "$dir" ]; echo $?
é um código de shell que lê um caminho de stdin e gera 0
se for um diretório, senão 1
print $6 |& cmd
canaliza o nome do arquivo para o comando. |&
é uma extensão do GNU-awk. cmd |& getline x
lê a saída do comando no GNU-awk close(cmd)
termina o comando, então a próxima linha pode executar novamente if (x)
executa o print
apenas se x
não for 0
(portanto, o diretório não existe) Eu não recomendo fazer assim, porque é muito lento e desajeitado. Mas esta receita é segura , tal que a entrada irregular não pode causar danos. (É improvável que /etc/passwd
contenha dados prejudiciais, mas talvez alguém queira usá-lo com dados de uma fonte não confiável).
Se você não pode usar gawk
, isso é lamentável. Nesse caso, você não tem |&
. Somente awk
normal pode fazer um dos três seguintes:
print "data" | cmd; close(cmd)
: dados de tubulação em um comando getline data < cmd; close(cmd)
: ler dados de um comando ret = system(cmd)
: obtenha o código de retorno do comando "Normal" awk
simplesmente não pode enviar dados para um script e obter algo novamente ao mesmo tempo (pelo menos eu não encontrei um caminho para isso), então você precisa de algum arquivo intermediário (tempfile) que é ainda mais desajeitado.
A observação interessante é que uma tarefa tão fácil pode ser feita apenas com o shell:
dump_problems()
{
have=0;
while IFS=: read -r user pw id grp gcos dir shl;
do
[ -d "$dir" ] && continue;
echo "$user $id $shl";
have=1;
done </etc/passwd;
return $have;
}
dump_problems && echo ALL OK >&2 || echo "Problems were found" >&2
Você não precisa de bash
, cada Bourne-shell normal pode executar o código acima.
Observe que o código shell acima é um pouco mais elaborado do que o realmente necessário, mas isso deve ser um indicador de como realmente trabalhar com ele (para pessoas que não têm experiência completa em como o shell funciona).