使用制表符分隔文件中字段的 space 分隔参数
Using space-separated arguments from a field in a tab-separated file
我正在编写一个 shell 脚本,旨在使用 sox 命令编辑音频文件。我已经 运行 遇到一个奇怪的问题,我以前在 bash 脚本中从未遇到过:在 sox 中定义 space 分离效果时,该命令将在直接写入该效果时起作用,但不会当它存储在变量中时。这意味着以下工作正常并且没有任何问题:
sox ./test.in.wav ./test.out.wav delay 5
但由于某些原因,以下方法不起作用:
IFS=' ' # set IFS to only have a tab character because file is tab-separated
while read -r file effects text; do
sox $file.in.wav $file.out.wav $effects
done <in.txt
...当其 in.txt
创建时:
printf '%s\t%s\t%s\n' "test" "delay 5" "other text here" >in.txt
错误表明这是导致它将输出文件视为另一个输入。
sox FAIL formats: can't open input file `./output.wav': No such file or directory
我尝试了所有我能想到的方法:使用引号 (sox "$file.in.wav" "$file.out.wav" "$effects"
),内联变量回显 (sox $file.in.wav $file.out.wav $(echo $effects)
),甚至转义变量内的 space ( effects="delay\ 5"
)。似乎什么都不起作用,一切都会产生错误。为什么一个命令有效而另一个无效,我缺少什么以及如何解决它?
IFS
不仅改变了 read
的行为;它还更改了未引用扩展的行为。
特别是,未加引号的扩展的内容在 IFS 中找到的字符上被拆分,然后拆分产生的每个元素被扩展为一个 glob。
因此,如果要将delay
和5
之间的space用于分词,则需要有一个正则的space,而不仅仅是一个选项卡,在 IFS
中。如果您将 IFS
赋值移动到与 read
相同的 简单命令 的一部分,就像 IFS=$'\t' read -r file effects text; do
中一样,这将阻止它改变脚本其余部分的行为。
但是,使用不带引号的扩展来进行分词根本不是一个好习惯。请改用数组。您可以将 effects
字符串拆分为一个数组:
IFS=' ' read -r -a effects_arr <<<"$effects"
...然后 运行 sox "$file.in.wav" "$file.out.wav" "${effects_arr[@]}"
将数组中的每个项目展开为一个单独的词。
相比之下,如果您需要 quotes/escapes/etc 在 effects
中被允许,请参阅 Reading quoted/escaped arguments correctly from a string
我正在编写一个 shell 脚本,旨在使用 sox 命令编辑音频文件。我已经 运行 遇到一个奇怪的问题,我以前在 bash 脚本中从未遇到过:在 sox 中定义 space 分离效果时,该命令将在直接写入该效果时起作用,但不会当它存储在变量中时。这意味着以下工作正常并且没有任何问题:
sox ./test.in.wav ./test.out.wav delay 5
但由于某些原因,以下方法不起作用:
IFS=' ' # set IFS to only have a tab character because file is tab-separated
while read -r file effects text; do
sox $file.in.wav $file.out.wav $effects
done <in.txt
...当其 in.txt
创建时:
printf '%s\t%s\t%s\n' "test" "delay 5" "other text here" >in.txt
错误表明这是导致它将输出文件视为另一个输入。
sox FAIL formats: can't open input file `./output.wav': No such file or directory
我尝试了所有我能想到的方法:使用引号 (sox "$file.in.wav" "$file.out.wav" "$effects"
),内联变量回显 (sox $file.in.wav $file.out.wav $(echo $effects)
),甚至转义变量内的 space ( effects="delay\ 5"
)。似乎什么都不起作用,一切都会产生错误。为什么一个命令有效而另一个无效,我缺少什么以及如何解决它?
IFS
不仅改变了 read
的行为;它还更改了未引用扩展的行为。
特别是,未加引号的扩展的内容在 IFS 中找到的字符上被拆分,然后拆分产生的每个元素被扩展为一个 glob。
因此,如果要将delay
和5
之间的space用于分词,则需要有一个正则的space,而不仅仅是一个选项卡,在 IFS
中。如果您将 IFS
赋值移动到与 read
相同的 简单命令 的一部分,就像 IFS=$'\t' read -r file effects text; do
中一样,这将阻止它改变脚本其余部分的行为。
但是,使用不带引号的扩展来进行分词根本不是一个好习惯。请改用数组。您可以将 effects
字符串拆分为一个数组:
IFS=' ' read -r -a effects_arr <<<"$effects"
...然后 运行 sox "$file.in.wav" "$file.out.wav" "${effects_arr[@]}"
将数组中的每个项目展开为一个单独的词。
相比之下,如果您需要 quotes/escapes/etc 在 effects
中被允许,请参阅 Reading quoted/escaped arguments correctly from a string