我想找一个bash命令,让我grep目录中的每个文件,并将该grep的输出写入一个单独的文件。我的猜测是做这样的事情
ls -1 | xargs -I{} "grep ABC '{}' > '{}'.out"
但据我所知,xargs不喜欢双引号。但是,如果我删除双引号,则命令会将整个命令的输出重定向到名为“{}”的单个文件。而不是一系列单个文件。
有没有人知道使用xargs做到这一点的方法?我只是用这个grep场景作为例子来说明我对xargs的问题,所以任何不使用xargs的解决方案都不适用于我。
答案 0 :(得分:176)
不要犯这样的错误:
sh -c "grep ABC {} > {}.out"
这将在很多条件下破解,包括时髦的文件名,并且无法正确引用。您的{}
必须始终是命令的一个完全独立的参数,以避免代码注入错误。你需要做的是:
xargs -I{} sh -c 'grep ABC "$1" > "$1.out"' -- {}
适用于xargs
以及find
。
顺便说一句,永远不要使用没有-0
选项的xargs(除非非常罕见且受控制的一次性交互式使用,你不担心会破坏你的数据)。
也不要解析ls
。永远。请改用globbing或find
: http://mywiki.wooledge.org/ParsingLs
对于需要递归的所有内容使用find
,并为其他所有内容使用带循环的简单循环:
find /foo -exec sh -c 'grep "$1" > "$1.out"' -- {} \;
或非递归:
for file in *; do grep "$file" > "$file.out"; done
注意正确使用引号。
答案 1 :(得分:38)
没有xargs
的解决方案如下:
find . -mindepth 1 -maxdepth 1 -type f -exec sh -c "grep ABC '{}' > '{}.out'" \;
......使用 xargs
也可以这样做,事实证明:
ls -1 | xargs -I {} sh -c "grep ABC '{}' > '{}.out'"
编辑:lhunath备注后添加的单引号。
答案 2 :(得分:14)
我认为你的例子只是一个例子,你可能需要>其他的东西。 GNU Parallel http://www.gnu.org/software/parallel/可能是你的救援。只要您的文件名不包含\ n:
,它就不需要额外的引用ls | parallel "grep ABC {} > {}.out"
如果您的文件名包含\ n:
find . -print0 | parallel -0 "grep ABC {} > {}.out"
作为额外奖励,您可以并行运行作业。
编辑。
您可以通过以下方式安装GNU Parallel:
wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
观看介绍视频以了解详情:http://pi.dk/1
10秒安装:
wget pi.dk/3 -qO - | sh -x