bash:获得第n列输出的最短路径

Sv1*_*Sv1 148 bash awk

假设您在工作日期间反复遇到bash中某些命令的以下形式的列化输出(在我的情况下,svn st在我的Rails工作目录中执行):

?       changes.patch
M       app/models/superman.rb
A       app/models/superwoman.rb
Run Code Online (Sandbox Code Playgroud)

为了使用命令的输出 - 在这种情况下是文件名 - 需要某种解析,以便第二列可以用作下一个命令的输入.

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

svn st | awk '{print $2}' | xargs rm
Run Code Online (Sandbox Code Playgroud)

由于我输入了很多,一个自然的问题是:在bash中有没有更短(更酷)的方法来实现这一点?

注意:我所要求的实际上是一个shell命令问题,即使我的具体示例是在我的svn工作流程上.如果您认为工作流程很愚蠢并建议另一种方法,我可能不会投票给您,但其他人可能会,因为这里的问题实际上是如何以最短的方式获得bash中的第n列命令输出.谢谢 :)

por*_*ges 104

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

cut -f2
Run Code Online (Sandbox Code Playgroud)

编辑:对不起,没有意识到SVN在其输出中没有使用制表符,所以这有点无用.你可以定制cut输出,但它有点脆弱 - 类似的cut -c 10- 工作,但确切的值将取决于你的设置.

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

  • 将适当的分隔符传递给`-d`可以使其正常工作. (15认同)
  • 为了扩展@Yogh所说的,对于空格作为分隔符,它看起来像`cut -d"" - f2`. (4认同)

Ric*_*key 91

完成同样的事情:

svn st | awk '{print $2}' | xargs rm
Run Code Online (Sandbox Code Playgroud)

只使用bash你可以使用:

svn st | while read a b; do rm "$b"; done
Run Code Online (Sandbox Code Playgroud)

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

  • @Timo `a` 表示第一列,`b` 表示其余列。如果要打印第二列,请使用 `read abc;`,然后使用 `echo` 而不是 `rm`。我用它来获得一堆遵循 grep 模式的 ID 进程,所以我可以中断它们。 (2认同)

Sta*_*ked 30

我发现自己处于相同的情况,最后将这些别名添加到我的.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}'"
Run Code Online (Sandbox Code Playgroud)

这允许我写这样的事情:

svn st | c2 | xargs rm
Run Code Online (Sandbox Code Playgroud)

  • Bash函数通常更有用.我这样做了:`function c(){awk"{print\$$ 1}"}`那么你可以这样做:`svn st | c 2 | xargs rm` (12认同)
  • 但是然后我需要输入一个额外的空格。太累了:) (5认同)

Chr*_*ris 15

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

alias -g X="| cut -d' ' -f2"
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

cat file X
Run Code Online (Sandbox Code Playgroud)

您可以更进一步,为第n列定义它:

alias -g X2="| cut -d' ' -f2"
alias -g X1="| cut -d' ' -f1"
alias -g X3="| cut -d' ' -f3"
Run Code Online (Sandbox Code Playgroud)

这将输出文件"file"的第n列.您也可以为grep输出或更少的输出执行此操作.这非常方便,是zsh的杀手级功能.

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

alias -g D="|xargs rm"
Run Code Online (Sandbox Code Playgroud)

现在你可以输入:

cat file X1 D
Run Code Online (Sandbox Code Playgroud)

删除文件"file"第一列中提到的所有文件.

如果您知道bash,除了一些新功能之外,zsh并没有太大的变化.

HTH Chris


tri*_*eee 8

因为您似乎不熟悉脚本,所以这是一个例子.

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

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

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

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


用法

给定一个文件file:

1 2 3
4 5 6
Run Code Online (Sandbox Code Playgroud)

你可以通过stdin传递它(仅使用一个无用cat的占位符来获得更有用的东西);

$ cat file | sh script.sh 2
2
5
Run Code Online (Sandbox Code Playgroud)

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

$ sh script.sh 2 file
2
5
Run Code Online (Sandbox Code Playgroud)

这里sh script.sh假设脚本保存script.sh在当前目录中; 如果你在你的某个地方用一个更有用的名字保存它并将其PATH标记为可执行文件,就像上面的说明一样,显然使用有用的名称(而不是sh).


Tar*_*del 5

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

  • 然后不要将其放在您的.bashrc中。在〜/ bin中创建一个脚本,并确保它在您的PATH中。 (4认同)
  • `.bashrc`?您为什么会用与非bash相关的东西弄乱它。我要做的是为每个“命令集”编写单独的脚本,并将它们全部放在“〜/ scripts”目录中。然后将整个〜/ scripts添加到我的PATH中,这样我就可以在需要时按名称调用它们。 (2认同)