如果我有一个文件列表,其中一些文件的名称中有空格,生成自,例如:
find . -iname "*hs" | grep foo
如何将它们作为参数传递给单个进程,例如process name1 name2 ...
?
请注意,我想将所有文件名作为单独的参数传递给单个进程,因此标准for f in *
解决方案不起作用
find . -iname "*hs*" -exec grep foo {} +
find . -iname "*hs*" -print0 | xargs -0 grep foo
两者都有效;第一个甚至可能更有效,除非该+
选项将更少的文件组合到命令行xargs
中。
如果您通过 shell globbing 生成文件名,则:
grep foo *hs*
保留文件名中的间距。用于ls
生成名称是非常有问题的。
grep 命令旨在在批量处理之前过滤文件名列表,而不是搜索文件本身的内容。
所以你想要同时匹配' hs '和' foo '的名字?在这种情况下,你最好find
还是使用:
find . \( -iname "*hs*" -a -iname "*foo*" \) -exec grep foo {} +
使用find
.
grep
扩展-Z
和-z
如果你不能这样做(你的grep
正则表达式需要太复杂find
),那么你就会遇到困难,除非你有一个(假设的?)版本grep
,它将读取由空值分隔的“行”。
-Z
,--null
输出一个零字节(ASCII NUL 字符)而不是通常跟在文件名后面的字符。例如,grep -lZ
在每个文件名之后输出一个零字节,而不是通常的换行符。此选项使输出明确,即使存在包含不寻常字符(如换行符)的文件名。此选项可与 、 、 和 等命令一起使用find -print0
,perl -0
以sort -z
处理xargs -0
任意文件名,即使是那些包含换行符的文件名。
这几乎是我们想要的,但不完全是。POSIX 2008getdelim()
函数将是使用的工具;为此目的添加一个-z
选项grep
,然后grep -lzZ ....
在将find ... -print0
数据馈送到xargs -0
.
上面的引用来自 Mac OS X 10.7.5 的手册页,GNUgrep
是 2.5.1 版。也许更新版本的 GNUgrep
可以更好地提供帮助?
你瞧,GNU grep
2.14 支持必要的选项:
-z
,--null-data
将输入视为一组行,每行都以零字节(ASCII NUL 字符)而不是换行符结尾。与-Z
or--null
选项一样,此选项可以与 'sort -z' 之类的命令一起使用,以处理任意文件名。
find
另一个不容忽视的选项是创建一个由find
命令运行的脚本:
find . -iname "*hs*" -exec ./list-foo +
list-foo
脚本可能在哪里:
for arg in "$@"
do
case "$arg" in
(*foo*) echo "$arg";; # This will still cause problems
esac
done
这标识了文件;这echo
是次优的。也许您需要捕获数组中的名称,然后使用数组调用最终命令:
array=( )
i=0
for arg in "$@"
do
case "$arg" in
(*foo*) array[$((i++))]="$arg";;
esac
done
if [ "$i" -gt 0 ]
then real_work "${array[@]}"
fi
real_work
真正起作用的程序(脚本?)在哪里。完成后你可以扔掉list-foo
它,除非你要一遍又一遍地做同样的过滤工作。
您可以通过转义空格来全局包含空格的名称:
rm -i -- *\ *
这将扩展到名称中带有空格的文件名,这有助于清理文件名包含为测试此问题的答案而创建的文件的目录。