Escapando variáveis ​​gawk para comandos shell

Escapando variáveis ​​gawk para comandos shell

Estou tentando executar um pequeno script gawk que executará determinados comandos do shell usando system(). Quero obter a lista de arquivos finde executar o script assim:

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

O problema é que esses arquivos possuem caracteres especiais como espaços, aspas e parênteses. Por exemplo:

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

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

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

E isto:

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

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

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

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

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 usa2variáveis ​​​​awk. Exemplos:

Se eu correr:

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

Não recebo erro porque cito FILEe porque não contém aspas duplas, tudo corre bem.

Mas se eu correr:

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

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

Responder1

Você poderia substituir system("<command> \"$0\"")pela capacidade do awk de escrever em um processo, ou seja print $0 | "pre;<command> \"$v\"", onde opréparte 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 de arquivos, você pode seguir a rota print0 no seu find e, se o seu awk aceitar RS='\0', você terá para o bash:

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

Responder2

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

Alternativamente, se o seu shell fornecer um especificador de formato de aspas de shell, você pode considerar usá-lo no lugar de findinternal -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 printfdentro, bashpor exemplo:

%q  quote the argument in a way that can be reused as shell input

informação relacionada