我正在尝试运行一个小的 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 脚本传递到 shell 命令,而不会遇到所有这些问题?
笔记:我知道暂时重命名文件可能会更容易,但我发现避免它更具挑战性。
编辑:
建议的答案都没有解决我的问题,因此这里是问题的更具体描述:我正在尝试运行一个使用的命令2awk 变量。例子:
如果我运行:
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 读入 shell 变量 v。在 bash 中,这将是read -r v
.例如,你最终会得到这样的结果:
awk 'BEGIN{ cmd="read -r v; ls -ld \"$v\"" }
{ print $0 | cmd; close(cmd); }'
如果你想处理可怕的事情,比如文件名中的换行符,你可以在 find 中使用 print0 路径,如果你的 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
或者,如果您的 shell 提供了 shell-quote 格式说明符,您可以考虑使用它来代替 的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
help printf
例如来自bash
:
%q quote the argument in a way that can be reused as shell input