Passando argumentos para o script awk

2

Eu tenho um script awk onde eu quero ser capaz de passar N argumentos para ele e também ler de stdin. Eu gostaria de poder fazer algo como

tail -f logfile | my_cool_awk_scipt var1 var2 var3 ... varN

E, em seguida, use essas variáveis dentro do script.

#!/bin/awk -f

BEGIN { 
print "AWK Script Starting" 
print ARGV[1]
}                                                                              
{
    if ($0 < ARGV[1])
        print $0
    else if ($0 < ARGV[2])
        print $0 + ARGV[2]             
}

Se eu tentar passar as variáveis como estão, imprima ARGV[1] e, em seguida, clique em

awk: ./my_cool_awk_script:4: fatal: cannot open file 'var1' for reading (No such file or directory)

eu posso fazer,

tail -f logfile | my_cool_awk_scipt -v var1=var1 -v var2=var2 -v var3=var3 ... varN=varN

mas isso é um pouco limitante e detalhado. Eu sei que eu também posso envolver isso em um script de shell, mas tenho certeza de uma maneira limpa de incorporar o que eu tenho em algo parecido.

Obrigado em avançado.

    
por AdamR 03.08.2018 / 17:50

4 respostas

0

No momento em que o awk atingir o corpo principal do script, após BEGIN , será necessário ler os nomes de arquivos especificados em ARGV [x]. Então, apenas nuke 'em.

$ cat a.awk
#!/bin/awk -f
BEGIN {
print "AWK Script Starting"
ZARGV[1]=ARGV[1]
ZARGV[2]=ARGV[2]
ARGV[1]=""
ARGV[2]=""
}
{
    if ($0 < ZARGV[1])
        print $0
    else if ($0 < ZARGV[2])
        print $0 + ZARGV[2]
}
$

Exemplo:

$ cat logfile
1
2
3
4
5
$ ./a.awk 3 4 <logfile
AWK Script Starting
1
2
7
$
    
por 03.08.2018 / 18:12
0

Você já conhece o -v variable=value . A outra maneira é passar variáveis pelo ambiente e lê-las a partir da matriz ENVIRON :

$ var1=hello var2=world awk 'BEGIN { print ENVIRON["var1"], ENVIRON["var2"] }'
hello world

Isso define apenas as variáveis de ambiente var1 e var2 no ambiente awk .

Ou

$ export var1=hello var2=world
$ awk 'BEGIN { print ENVIRON["var1"], ENVIRON["var2"] }'
hello world

Isso define as variáveis no ambiente de chamada antes de chamar awk .

A matriz ARGV contém apenas os nomes de arquivos que o programa awk lerá em sequência, mas também pode conter nomes de variáveis definidos na linha de comando, como em

awk '...' var1=value1 var2=value2 filename

Geralmente não é uma maneira recomendada de passar variáveis para awk (essas variáveis não estariam disponíveis em um bloco BEGIN , por exemplo).

    
por 03.08.2018 / 17:57
0

Você pode criar um script como este:

#!/bin/bash   
vars=()
i=1
for arg in "$@"; do
    vars+=(-v "var$i=$arg")
    i=$((i+1))
done

awk "${vars[@]}" -f/dev/fd/3 3<< EOF
BEGIN {
    printf "awk var1: %s\n", var1;
    printf "awk var2: %s\n", var2;
}
1
EOF

e, em seguida, execute-o:

$ echo some input | ./awk.sh foo bar doo
awk var1: foo
awk var2: bar
some input

O script de shell criará uma linha de comando desses -v var1=... argumentos e os passará para awk , com o programa awk real por meio de um here-doc (é claro que você pode ter o script awk em um arquivo separado em vez de). Você não pode passar nenhum nome dos arquivos de entrada dessa maneira, mas é forçado a ler o script awk do stdin.

Pelo menos o GNU awk documenta explicitamente que ARGV[n] também são usados como arquivos de entrada ( link ), e é por isso que você obtém os erros" arquivo não encontrado ".

    
por 03.08.2018 / 18:06
0

Apenas pela diversão (e isso certamente NÃO é a maneira recomendada de fazer isso): Como awk não sabe sobre "parâmetros posicionais" (PP), mas apenas atribuições de variáveis e nomes de arquivos de entrada, precisamos dissecar o PP e informá-los dos outros dois. Isto pode ser feito separando o PP com um token fixo, por ex. -- (que tamb utilizado noutro contexto), ou conhecendo a contagem de PP, fixos ou transportados em, e. ARGV [1]). Experimente

    awk '
    BEGIN   {while (ARGV[++MXPP] != "--")   PP[MXPP]     = ARGV[MXPP]
             for (j=MXPP+1; j<ARGC; j++)    ARGV[j-MXPP] = ARGV[j]
             ARGC -= --MXPP
            }

            {if ($0 < ARGV[1])
             print $0
             else if ($0 < ARGV[2])
             print $0 + ARGV[2]             
            }
    ' VAR1 VAR2 -- file[12]

Se você usar stdin no lugar de arquivos de entrada pelo piping sth in, você poderá omitir o token e buscar o PP até o final da lista (ou seja, definir o token como "")

    
por 03.08.2018 / 19:21