以下是一个简单的Bash命令行:
grep -li 'regex' "filename with spaces" "filename"
没有问题。另外,以下内容也完全可以正常工作:
grep -li 'regex' $(<listOfFiles.txt)
当 listOfFiles.txt
包含要进行 grep 的文件名列表时,每行一个文件名。
问题出现在 listOfFiles.txt
中包含带有空格的文件名。在我尝试过的所有情况中(见下文),Bash 都会将文件名在空格处分割,因此,例如包含像 ./this is a file.xml
这样的名称的 listOfFiles.txt
行最终会尝试对每个部分(./this
、is
、a
和 file.xml
)运行 grep。
我认为自己是一个相对高级的 Bash 用户,但我找不到一个简单的魔法咒语来解决这个问题。以下是我尝试过的方法。
grep -li 'regex' `cat listOfFiles.txt`
与上述描述一样失败了(我并没有真正期望这会成功),因此我想给每个文件名加引号:grep -li 'regex' `sed -e 's/.*/"&"/' listOfFiles.txt`
Bash把引号当作文件名的一部分, 对于每个文件都会报"没有这样的文件或目录"错误(而且仍然使用空格分隔文件名)。
for i in $(<listOfFiles.txt); do grep -li 'regex' "$i"; done
原始尝试失败了(即,它的行为就像引号被忽略一样),而且速度很慢,因为它必须针对每个文件启动一个“grep”进程,而不是在一个调用中处理所有文件。
以下方法可以运行,但如果正则表达式包含shell元字符,则需要注意仔细的双重转义:
eval grep -li 'regex' `sed -e 's/.*/"&"/' listOfFiles.txt`
这是构建命令行以正确处理带空格文件名的唯一方法吗?
FOO=bar; echo $FOO
,然后在另一行上运行echo $FOO
。管道命令会自动启动子shell,但是IFS=$'\n'
当然不是管道的一部分。最好的解决方案是用括号将整个语句括起来,这样可以手动告诉bash在子shell中运行命令。 - CascabelIFS=$'\n'
的范围在这种情况下非常有限,甚至不适用于$(<listOfFiles.txt)
? - Stephan202seq 0 9 | xargs -I{} sh -c 'echo {} > "{} {}.txt"; echo "{} {}.txt" >> listOfFiles.txt' && (IFS=$'\n'; grep -li '[0-5]' $(<listOfFiles.txt))
)。 - Stephan202