Bash:获取输出的第n列的最短方法

让我们假设在你的工作日中,你在bash中的某些命令中反复遇到以下形式的柱状输出(在我的情况下,在我的Rails工作目录中执行svn st):

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

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

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

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

由于我经常键入这个,一个自然的问题是:在bash中是否有更短(因此更酷)的方法来完成这个任务?

< p >注意: 我问的本质上是一个shell命令问题,尽管我的具体示例是在svn工作流上。如果您觉得工作流很愚蠢,并建议采用另一种方法,我可能不会反对,但其他人可能会反对,因为这里的问题实际上是如何以尽可能短的方式在bash中获得第n列命令输出。谢谢:)< / p >
314988 次浏览

看起来你已经有了一个解。为了使事情变得更简单,为什么不把命令放在bash脚本中(使用短名称),然后运行该脚本,而不是每次都输入“长”命令呢?

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

cut -f2
< p >编辑: 对不起,我没有意识到SVN在输出中不使用选项卡,所以这有点没用。你可以为输出定制cut,但它有点脆弱——像cut -c 10-这样的东西可以工作,但确切的值将取决于你的设置

另一个选项类似于:sed 's/.\s\+//'

试试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"

它将输出文件“file”的第n列。您也可以为grep输出或更少的输出执行此操作。这非常方便,是zsh的一个杀手级特性。

你可以更进一步,定义D为:

alias -g D="|xargs rm"

现在你可以输入:

cat file X1 D

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

如果您了解bash,那么zsh除了一些新特性之外没有太大变化。

HTH克里斯

完成的事情与:

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

只使用bash可以使用:

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

当然,它不是更短,但它更有效,它正确地处理文件名中的空白。

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

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

如果你把它保存在~/bin/x中,并确保~/bin在你的PATH中(现在这是你可以而且应该放在.bashrc中的东西),你就有了通常提取列n的最短命令;x n。

脚本应该做适当的错误检查和保释,如果调用非数字参数或不正确的参数数量,等等;但扩展这个基本的基本版本将在102单元。

也许您希望扩展脚本以允许使用不同的列分隔符。默认情况下,Awk在空格中解析输入字段;要使用不同的分隔符,请使用-F ':',其中:是新的分隔符。将它作为脚本的一个选项来实现会使它稍微长一些,所以我把它留给读者作为练习。


使用

给定一个文件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)。

注意,文件路径不必在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。

如果你可以手动选择列,你可以非常快地使用< >强选择< / >强:

svn st | pick | xargs rm

只要转到第二列的任意单元格,按c,然后按enter

我发现自己也有同样的情况,并最终将这些别名添加到我的.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