如何表达“将linux命令映射到文件中的每一行”?

时间:2010-09-24 18:44:29

标签: linux awk

我经常需要删除不在特定svn源代码树中的所有文件。要获取所有文件名列表,我使用:

svn st | grep ^? | awk '{print $2}'

这个命令会给我一个文件名列表,每行一个名字。那么我该如何表达

的想法
for (each line in ${svn st | grep ^? | awk '{print $2}' )
    rm -f line

5 个答案:

答案 0 :(得分:5)

使用xargs:

svn st | grep '^?' | awk '{print $2}' | xargs rm -rf

注意:在命令中,由于{print $2},您不处理具有空格的文件。你还必须小心xargs因为它在空格上分割它的输入。因此,如果文件名中有空格,则使用-0选项会更安全。

这是一个更正确的xargs用法示例:

find -type f| tr \\n \\0 | xargs -0 wc

或者,使用find -print0选项:

find -type f -print0 | xargs -0 wc 

xargs是最强大的UNIX工具之一。我每天都用它。

答案 1 :(得分:2)

为什么有这么多人在管道中调用grep并且在他们有血腥时使用bash的{​​{1}}循环或后端for事情中间有xargs 吗?

首先让我们摆脱grep的异想天开的使用:

awk

由于svn st | awk '/^?/ { print $2 }' 允许您根据正则表达式过滤行,因此完全不需要使用grep。 awk的正则表达式与awk没有什么不同(取决于grep的哪个实现以及您正在使用的awk中的哪个),为什么要添加一个全新的流程和管道中的一个新瓶颈?

从那里你已经有两个更短,更可读的选择:

grep

现在第二个选项只有在你的文件列表没有超过最大命令行大小时才有效,所以我推荐使用xargs版本。

或者,甚至可能更好,再次使用# option 1 svn st | awk '/^?/ { print $2 }' | xargs rm -f # option 2 rm -f $(svn st | awk '/^?/ { print $2 }')

awk

这将与您在上面使用svn st | awk '/^?/ { system("rm -f $2") }' 循环所做的功能等效。它看起来非常低效,因为它会为每个文件执行一次rm,但它至少比你的for循环示例更具可读性。然而,它可以进一步改善。我不会在这里详细介绍,但会给你评论作为最终解决方案的线索。

for

好的,所以最后一个有点拗口,太多了,不能打电话作为常规的单线。但是,由于您必须“经常”执行此操作,因此将其放入脚本中应该不会太糟糕:

svn st | awk 'BEGIN{ /*set up an array*/ }; /^?/ { /*add $2 to the array*/ }; END{ /*system("rm -f ...") safe chunks of the array*/}

现在您的命令行将是#!/usr/bin/env awk BEGIN { /* set up your accumulator array */ } /^?/ { /* add $2 to the array */ } END { /* invoke system("rm -f") on safe chunks of the accumulator array */ }

现在我会警告你,我没有能力检查所有这些(因为我避免使用SVN和CVS,就像我避免使用MS-DOS一样 - 并且出于同样的原因)。例如,您可能不得不在脚本中使用svn st | myawkscript行,或者使用您用于过滤的正则表达式,但一般原则仍然大致相同。而我个人?我会使用#!来做我不常做的事情。我只会为我每周做几次或更多次的事情做完整的脚本。

答案 2 :(得分:0)

有几种方法可以解决相关的各种缺点...其中一个更简单的方法是使用while read..循环。另一种方法是使用for循环并将IFS更改为\n,但这有点丑陋而没有任何好处。你可能会看到它完成,特别是如果他们想要在空格上分词。

git status | while read line; do
    echo "I'm an albatross! $line"
done

或者,使用进程替换(除去可以添加nasty complications的子shell)

while read line; do
    echo "I'm an albatross! $line"
done <(git status)

有一些警告可能会使事情在特定情况下变得更加复杂。您应该阅读help readBash FAQ #1包含许多血腥的详细信息。

答案 3 :(得分:0)

使用反向标记使用命令替换:http://tldp.org/LDP/abs/html/commandsub.html

在你的情况下:

rm -f `svn st | grep ^? | awk '{print $2'}`

答案 4 :(得分:0)

xargs是你的朋友:

svn st | awk '/^?/{print $2}'|xargs rm -rf