Я пытаюсь запустить небольшой скрипт gawk, который будет запускать определенные команды оболочки с помощью system()
. Я хочу получить список файлов find
и запустить скрипт следующим образом:
find <arguments> -printf "%f\n" | script.awk
Проблема в том, что в этих файлах есть специальные символы, такие как пробелы, кавычки и скобки. Например:
$ ls
'Aujourd'\''hui C'\''est Toi (Orchestral).flac'
Я перепробовал всевозможные цитаты, например, такие:
system("<command> \""$0"\"")
И это:
system("<command> \'"$0"\'")
Я получаю всевозможные ошибки, некоторые из них связаны sh -c
с gawk
...
Есть ли способ передать запись $0
или любые другие переменные из скрипта gawk в команду оболочки, не сталкиваясь со всеми этими проблемами?
Примечание:Я знаю, что было бы проще просто временно переименовать файлы, но мне кажется сложнее этого избежать.
РЕДАКТИРОВАТЬ:
Ни один из предложенных ответов не решил мою проблему, поэтому вот более конкретное описание проблемы: Я пытаюсь запустить команду, которая использует2Переменные awk. Примеры:
Если я запущу:
system("metaflac --show-tag=ARTIST \""FILE"\"")
Я не получаю сообщение об ошибке, потому что я цитирую, FILE
и поскольку текст не содержит двойных кавычек, все проходит нормально.
Но если я запущу:
system("metaflac --set-tag=ARTIST="AWK_VAR_WITH_ARTIST_VALUE" "\"FILE\")
Даже когда я цитирую его, я получаю ошибку, metaflac
что файл flac не найден. При чтении сообщения об ошибке я вижу, что имя файла было разделено на отдельные слова.
решение1
Вы можете заменить system("<command> \"$0\"")
его способностью awk писать в процесс, т. е. print $0 | "pre;<command> \"$v\""
, гдепредварительночасть будет читать stdin в переменную оболочки v. В bash это будет read -r v
. Вы получите, например, это:
awk 'BEGIN{ cmd="read -r v; ls -ld \"$v\"" }
{ print $0 | cmd; close(cmd); }'
Если вы хотите справиться с ужасными вещами, такими как переводы строк в именах файлов, вы можете использовать маршрут print0 в вашем find и, если ваш awk принимает это RS='\0'
, для bash у вас есть:
find . -print0 |
awk -v RS='\0' '
BEGIN{ cmd="read -r -d \"\" v; ls -ld \"$v\"" }
{ print $0 "\x00" | cmd; close(cmd); }'
решение2
В конкретном случае пробелов и одинарных кавычек будет достаточно заключить строку в двойные кавычки:
$ 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
В качестве альтернативы, если ваша оболочка предоставляет спецификатор формата кавычек оболочки, вы можете рассмотреть возможность использования его вместо find
внутреннего -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
help printf
Например , из bash
:
%q quote the argument in a way that can be reused as shell input