Escapando variáveis do gawk para comandos do shell

2

Estou tentando executar um pequeno script gawk que executará determinados comandos do shell usando system() . Eu quero pegar a lista de arquivos com find e rodar o script assim:

find <arguments> -printf "%f\n" | script.awk

O problema é que esses arquivos têm caracteres especiais, como espaços, citações e parênteses. Por exemplo:

$ ls
'Aujourd'\''hui C'\''est Toi (Orchestral).flac'

Eu tentei todos os tipos de citações como as seguintes:

system("<command> \""$0"\"")

E isso:

system("<command> \'"$0"\'")

Recebo todos os tipos de erros, alguns desses erros são de sh -c e alguns são de gawk ...

Existe uma maneira de passar o registro $0 ou quaisquer outras variáveis do script gawk para um comando shell sem encontrar todos esses problemas?

Observação: sei que poderia ter sido mais fácil simplesmente renomear os arquivos temporariamente, mas acho mais difícil evitá-los.

EDITAR:

Nenhuma das respostas sugeridas resolveu meu problema, então aqui está uma descrição mais específica do problema: Estou tentando executar um comando que usa variáveis awk 2 . Exemplos:

Se eu correr:

system("metaflac --show-tag=ARTIST \""FILE"\"")

Eu não recebo um erro porque cito FILE e porque ele não contém aspas duplas, tudo bem.

Mas se eu correr:

system("metaflac --set-tag=ARTIST="AWK_VAR_WITH_ARTIST_VALUE" "\"FILE\")

Mesmo quando cito, recebo um erro de metaflac de que o arquivo flac não foi encontrado. Ao ler a mensagem de erro, vejo que o nome do arquivo foi dividido em palavras separadas.

    
por Doron Behar 26.05.2017 / 17:24

2 respostas

1

Você pode substituir system("<command> \"$0\"") pela capacidade do awk de gravar em um processo, ou seja, print $0 | "pre;<command> \"$v\"" , onde a parte pré leria stdin na variável shell v. No bash isso seria read -r v . Você acaba com isso, por exemplo:

awk 'BEGIN{ cmd="read -r v; ls -ld \"$v\"" }
     { print $0 | cmd; close(cmd); }'

Se você quiser lidar com coisas horríveis, como novas linhas nos nomes dos arquivos, você pode ir a rota print0 em seu find e, se o seu awk aceitar RS='%code%' , você tem por bash:

find . -print0 |
awk -v RS='
awk 'BEGIN{ cmd="read -r v; ls -ld \"$v\"" }
     { print $0 | cmd; close(cmd); }'
' ' BEGIN{ cmd="read -r -d \"\" v; ls -ld \"$v\"" } { print $0 "\x00" | cmd; close(cmd); }'
    
por 27.05.2017 / 11:41
0

Para o caso específico de espaços e aspas simples, deve ser suficiente colocar a string entre aspas duplas:

$ find -name 'Aujour*' -printf "%f\n" | awk '{system("ls -l \""$0"\"")}'
-rw-rw-r-- 1 user user 0 May 26 11:27 Aujourd'hui C'est Toi (Orchestral).flac

Como alternativa, se o seu shell fornecer um especificador de formato de cotação de shell, você poderá considerar o uso no lugar do find :

do -printf :

$ find -name 'Aujour*' -exec printf '%q\n' {} \; | awk '{system("ls -l "$0)}'
-rw-rw-r-- 1 user user 0 May 26 11:27 ./Aujourd'hui C'est Toi (Orchestral).flac

De help printf in bash , por exemplo:

%q  quote the argument in a way that can be reused as shell input
    
por 26.05.2017 / 18:03