182

我想找到一个 bash 命令,它可以让我 grep 目录中的每个文件并将该 grep 的输出写入单独的文件。我的猜测是做这样的事情

ls -1 | xargs -I{} "grep ABC '{}' > '{}'.out"

但是,据我所知, xargs 不喜欢双引号。但是,如果我删除双引号,那么该命令会将整个命令的输出重定向到一个名为 '{}'.out 的文件,而不是一系列单独的文件。

有谁知道使用 xargs 的方法吗?我只是以这个 grep 场景为例来说明我的 xargs 问题,因此任何不使用 xargs 的解决方案都不适用于我。

4

4 回答 4

222

不要犯这样的错误:

sh -c "grep ABC {} > {}.out"

这会在很多情况下中断,包括时髦的文件名,并且无法正确引用。您{}必须始终是命令的一个完全独立的参数,以避免代码注入错误。你需要做的是:

xargs -I{} sh -c 'grep ABC "$1" > "$1.out"' -- {}

适用于xargs以及find

顺便说一句,不要在没有-0选项的情况下使用 xargs(除非您不担心破坏数据的非常罕见且受控的一次性交互式使用)。

也不解析ls。曾经。使用通配符或find代替:http://mywiki.wooledge.org/ParsingLs

用于find需要递归的所有内容和一个简单的循环,其他所有内容都使用 glob:

find /foo -exec sh -c 'grep "$1" > "$1.out"' -- {} \;

或非递归:

for file in *; do grep "$file" > "$file.out"; done

注意正确使用引号。

于 2009-05-10T19:22:38.640 回答
45

没有的解决方案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备注后添加单引号。

于 2009-05-10T18:59:23.687 回答
14

我假设您的示例只是一个示例,您可能需要 > 来处理其他事情。GNU Parallel http://www.gnu.org/software/parallel/可能是你的救星。只要您的文件名不包含 \n,它就不需要额外的引用:

ls | parallel "grep ABC {} > {}.out"

如果您的文件名中包含 \n:

find . -print0 | parallel -0 "grep ABC {} > {}.out"

作为额外的奖励,您可以获得并行运行的作业。

观看介绍视频以了解更多信息:http: //pi.dk/1

10秒安装会尝试做完整安装;如果失败,个人安装;如果失败,最小安装:

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 883c667e01eed62f975ad28b6d50e22a
12345678 883c667e 01eed62f 975ad28b 6d50e22a
$ md5sum install.sh | grep cc21b4c943fd03e93ae1ae49e28573c0
cc21b4c9 43fd03e9 3ae1ae49 e28573c0
$ sha512sum install.sh | grep da012ec113b49a54e705f86d51e784ebced224fdf
79945d9d 250b42a4 2067bb00 99da012e c113b49a 54e705f8 6d51e784 ebced224
fdff3f52 ca588d64 e75f6033 61bd543f d631f592 2f87ceb2 ab034149 6df84a35
$ bash install.sh

如果您需要将其移至未安装 GNU Parallel 的服务器,请尝试parallel --embed.

于 2010-06-10T18:27:28.607 回答
1

实际上,这里的大多数答案都不适用于所有文件名(如果它们包含双引号和单引号),包括 lhunath 和 Stephan202 的答案。

此解决方案适用于带有单引号和双引号的文件名:

find . -mindepth 1 -print0 | xargs -0 -I{} sh -c 'grep ABC "$1" > "$1.out"' -- {}

这是一个带有单引号和双引号的文件名的测试:

echo ABC > "I'm here.txt"

# lhunath solution (hangs waiting for input)

$ find . -exec sh -c 'grep "$1" > "$1.out"' -- {} \;

# Stephan202 solutions

$ find . -mindepth 1 -maxdepth 1 -type f -exec sh -c "grep ABC '{}' > '{}.out'" \;
grep: ./Im: No such file or directory
grep: here.txt > ./Im here.txt.out: No such file or directory

$ ls -1 | xargs -I {} sh -c "grep ABC '{}' > '{}.out'"
xargs: unterminated quote

# this solution
$ find . -mindepth 1 -print0 | xargs -0 -I{} sh -c 'grep ABC "$1" > "$1.out"' -- {}

$ ls -1
"I'm here.txt"
"I'm here.txt.out"
于 2021-12-05T00:08:48.213 回答