Estoy intentando ejecutar un pequeño script gawk que ejecutará ciertos comandos de shell usando system()
. Quiero obtener la lista de archivos find
y ejecutar el script así:
find <arguments> -printf "%f\n" | script.awk
El problema es que estos archivos tienen caracteres especiales como espacios, comillas y paréntesis. Por ejemplo:
$ ls
'Aujourd'\''hui C'\''est Toi (Orchestral).flac'
Probé todo tipo de citas como las siguientes:
system("<command> \""$0"\"")
Y esto:
system("<command> \'"$0"\'")
Recibo todo tipo de errores, algunos de estos errores son de sh -c
y otros son de gawk
...
¿Hay alguna manera de pasar el registro $0
o cualquier otra variable del script gawk a un comando de shell sin encontrar todos estos problemas?
Nota:Sé que podría haber sido más fácil cambiar el nombre de los archivos temporalmente, pero me resulta más difícil evitarlo.
EDITAR:
Ninguna de las respuestas sugeridas resolvió mi problema, así que aquí hay una descripción más específica del problema: Estoy intentando ejecutar un comando que usa2variables extrañas. Ejemplos:
Si corro:
system("metaflac --show-tag=ARTIST \""FILE"\"")
No recibo ningún error porque cito FILE
y como no contiene comillas dobles, va bien.
Pero si ejecuto:
system("metaflac --set-tag=ARTIST="AWK_VAR_WITH_ARTIST_VALUE" "\"FILE\")
Incluso cuando lo cito, aparece un error que indica metaflac
que no se encontró el archivo flac. Al leer el mensaje de error, veo que el nombre del archivo se dividió en palabras separadas.
Respuesta1
Podrías reemplazarlo system("<command> \"$0\"")
por la capacidad de awk para escribir en un proceso, es decir print $0 | "pre;<command> \"$v\""
, dondepreparte leería stdin en la variable de shell v. En bash esto sería read -r v
. Terminas con esto, por ejemplo:
awk 'BEGIN{ cmd="read -r v; ls -ld \"$v\"" }
{ print $0 | cmd; close(cmd); }'
Si desea manejar cosas horribles como nuevas líneas en los nombres de archivos, puede ir a la ruta print0 en su búsqueda y, si su awk lo acepta RS='\0'
, tiene para bash:
find . -print0 |
awk -v RS='\0' '
BEGIN{ cmd="read -r -d \"\" v; ls -ld \"$v\"" }
{ print $0 "\x00" | cmd; close(cmd); }'
Respuesta2
Para el caso específico de espacios y comillas simples, debería ser suficiente encerrar la cadena entre comillas dobles:
$ 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, si su shell proporciona un especificador de formato de comillas de shell, podría considerar usarlo en 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
Desde help printf
en bash
por ejemplo:
%q quote the argument in a way that can be reused as shell input