bash:获得输出的第n列的最短方法


165

假设在您的工作日中,您反复遇到bash中某个命令的以下形式的列化输出形式(对于我而言,是svn st在我的Rails工作目录中执行):

?       changes.patch
M       app/models/superman.rb
A       app/models/superwoman.rb

为了处理命令的输出(在本例中为文件名),需要进行某种形式的解析,以便将第二列用作下一条命令的输入。

我一直在做的事情是使用awk第二列,例如,当我想删除所有文件(不是那是典型的用例:)时,我会这样做:

svn st | awk '{print $2}' | xargs rm

由于我输入了很多内容,一个自然的问题是:在bash中完成此操作的方法是否更短(因此更酷)?

注意:尽管我的具体示例在我的svn工作流程中,但我要问的实际上是一个shell命令问题。如果您认为工作流程很愚蠢,并且建议使用其他方法,那么我可能不会拒绝您,但是其他人可能会拒绝,因为这里的问题实际上是如何以最短的方式以bash格式输出第n列命令。谢谢 :)


1
使用命令时,通常最好创建一个脚本并将其放在路径中。如果您愿意,可以在bashrc中简单地创建一个函数。我看不出减少列选择表达式的意义。
Lynch

1
您说得对,我可能会这样做。“要点”是寻求以新方式做bash的目的,以学习为目的,但主要是为了娱乐:)
Sv1

1
另外,在某处ssh-ing时您没有.bashrc,因此了解没有它的方法很有用。
2014年

Answers:


125

您可以使用cut访问第二个字段:

cut -f2

编辑:对不起,没有意识到SVN在其输出中不使用制表符,所以这有点没用。您可以定制cut输出,但是有点脆弱- cut -c 10- 可能会起作用,但是确切的值取决于您的设置。

另一种选择是这样的: sed 's/.\s\+//'


1
尝试cut -f2svn st输出配合使用。您将看到它不起作用。
Lynch

我假设实际svn st将在其输出中使用制表符。经过一些测试,似乎并非如此。该死的。
porges 2011年

21
传递适当的定界符以-d允许它起作用。
Yogh

6
为了扩展@Yogh所说的内容,对于空格作为分隔符,它看起来像cut -d" " -f2
adamyonk

在标准输出上不使用awk,使用xargs:svn st | xargs | 切-d“” -f2
vr286 '18

106

要完成以下任务:

svn st | awk '{print $2}' | xargs rm

仅使用bash即可使用:

svn st | while read a b; do rm "$b"; done

当然,它并不短,但效率更高,并且可以正确处理文件名中的空格。


什么是ab,如何获得它们?
Timo

1
@Timo a代表第一列,b代表其余列。如果要打印第二列,请使用read a b c;,然后使用echo代替rm。我用它来获得遵循grep模式的一堆ID流程,因此我可以全部中断它们。
马特·克莱因史密斯

36

我发现自己处在相同的情况下,最终将这些别名添加到我的.profile文件中:

alias c1="awk '{print \$1}'"
alias c2="awk '{print \$2}'"
alias c3="awk '{print \$3}'"
alias c4="awk '{print \$4}'"
alias c5="awk '{print \$5}'"
alias c6="awk '{print \$6}'"
alias c7="awk '{print \$7}'"
alias c8="awk '{print \$8}'"
alias c9="awk '{print \$9}'"

这使我可以编写如下内容:

svn st | c2 | xargs rm

15
Bash函数通常更有用。我这样做了: function c() { awk "{print \$$1}" } 然后您可以这样做: svn st | c 2 | xargs rm
艾森(Aissen)

8
但是然后我需要输入一个额外的空格。太累了:)
StackedCrooked

16

尝试zsh。它支持后缀别名,因此您可以在.zshrc中将X定义为

alias -g X="| cut -d' ' -f2"

那么您可以执行以下操作:

cat file X

您可以进一步将其定义为第n列:

alias -g X2="| cut -d' ' -f2"
alias -g X1="| cut -d' ' -f1"
alias -g X3="| cut -d' ' -f3"

这将输出文件“文件”的第n列。您也可以为grep输出或更少的输出执行此操作。这非常方便并且是zsh的杀手级功能。

您可以再进一步一步,将D定义为:

alias -g D="|xargs rm"

现在您可以输入:

cat file X1 D

删除文件“文件”第一栏中提到的所有文件。

如果您了解bash,除了一些新功能外,zsh不会有太大变化。

克里斯


嗯,我看到您在上面输入我的评论时更新了您的答案:)您能以某种方式动态指定要获取的列,还是在我的.zshrc中需要n行(不是很重要,只是出于好奇)
Sv1

我进一步编辑了帖子,并定义了后缀“ D”以删除文件。据我所知,您将必须为每个后缀添加一行。
克里斯(Chris

或使其成为X命令的第一个参数。除了将管道放在别名中的特殊想法外,这些都不需要zsh或别名。
2011年

1
我不明白为什么大家似乎都喜欢这种cut选择。使用的输出,它根本无法在我的机器上运行svn st。尝试svn st | cut -d' ' -f2只是看看会发生什么。
林奇

@ Sv1您可以编写一个定义别名的循环,因为别名只是一个命令。
2013年

8

因为您似乎不熟悉脚本,所以这里有个例子。

#!/bin/sh
# usage: svn st | x 2 | xargs rm
col=$1
shift
awk -v col="$col" '{print $col}' "${@--}"

如果您将其保存在其中~/bin/x并确保~/bin在其中PATH(现在可以,应该将其放入您的.bashrc),那么您将使用最短的命令来提取第n列;n

如果使用非数字参数或不正确数量的参数等调用脚本,则脚本应进行正确的错误检查和保释;但在此基本基本版本上进行扩展将在单元102中进行。

也许您将需要扩展脚本以允许使用其他列分隔符。默认情况下,Awk将输入解析为空格中的字段;要使用其他定界符,请使用-F ':'where :是新的定界符。将其实现为脚本的一个选项会使它稍长一些,因此我将其留给读者练习。


用法

给定一个文件file

1 2 3
4 5 6

您可以通过stdin传递它(使用 cat无用的东西用作占位符,以获得更多有用的信息);

$ cat file | sh script.sh 2
2
5

或将其作为脚本的参数提供:

$ sh script.sh 2 file
2
5

这里,sh script.sh假设脚本已保存为script.sh当前目录中的内容;如果您使用更有用的名称保存它,并将其PATH标记为可执行文件(如上述说明中所示),则显然要使用该有用的名称(而不是sh)。


这是个好主意,但对我而言并不像在sh或bash上那样有效。这有效:#!/ bin / bash col = $ 1 shift awk“ {print \ $$ col}”
mgk 2015年

感谢您的最新评论。更新了您的修复程序。
2015年

1
更好awk -v col=$col ...
fedorqui'SO stop harm''Dec

@fedorqui感谢您在这里和其他地方的反馈!更新了答案。现在,它的长度略长,因此,如果您要使用绝对最短的脚本,请参阅原始版本的修订历史记录
2015年

1
@fedorqui谢谢大家!cat出于歇斯底里的原因,在示例中添加了一些警告(-:
Tripleee

5

看来您已经有了解决方案。为了使事情变得容易,为什么不将命令放在bash脚本中(使用短名称)并直接运行而不是每次都键入“ long”命令呢?


我认为它不那么“酷”。为什么?好吧,我不想让我的.bashrc泛滥成灾,而这简直就是编写了meta-shell。它的别名非常真实。话虽如此,您的建议也不错。
Sv1

2
.bashrc?您为什么会用非bash相关的东西来弄乱它。我要做的是为每个“命令集”编写单独的脚本,然后将它们全部放在~/scripts目录中。然后将全部内容添加~/scripts到我的列表中,PATH这样我就可以在需要时按名称调用它们。
塔雷克·法德尔

4
然后不要将其放在您的.bashrc中。在〜/ bin中创建一个脚本,并确保它在您的PATH中。
2011年

2

如果可以手动选择该列,则可以使用pick快速:

svn st | pick | xargs rm

只需转到第二列的任何单元格,按c,然后单击enter


我试用了您引用的“选择”工具,对此我非常喜欢。在很多情况下,我想打印选定的列,但不想输入“ awk'{print $ 3}'”只是为了获得所需的列,这非常好。不幸的是,该名称与另一个似乎更受欢迎的“ pick”工具冲突-可以使用“ apt install pick”安装它。因此,我在系统上将您的工具重命名为“ pickk”,并打算继续使用它。感谢您发布参考。
威廉·戴

1

注意,文件路径不必位于svn st输出的第二列。例如,如果您修改文件并修改其属性,它将是第三列。

在以下位置查看可能的输出示例:

svn help st

输出示例:

 M     wc/bar.c
A  +   wc/qax.c

我建议通过以下方式削减前8个字符:

svn st | cut -c8- | while read FILE; do echo whatever with "$FILE"; done

如果您想100%确定,并以例如结尾处带有空格的特殊文件名处理,则需要解析xml输出:

svn st --xml | grep -o 'path=".*"' | sed 's/^path="//; s/"$//'

当然,您可能希望使用某些真实的XML解析器而不是grep / sed。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.