Estou tentando executar um pequeno script gawk que executará determinados comandos do shell usando system()
. Quero obter a lista de arquivos find
e 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 -c
e outros são de gawk
...
Existe uma maneira de passar o registro $0
ou 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 FILE
e 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 metaflac
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.
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 find
internal -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
dentro, bash
por exemplo:
%q quote the argument in a way that can be reused as shell input