如何将命令输出中的单个项目传送到另一个命令?

如何将命令输出中的单个项目传送到另一个命令?

使用 grep 的基本示例(请注意,grep 不是我唯一的用例):

$ grep -Irl "foo"
path/to/directory/help.js
path/to/directory/config.js
path/to/directory/task.js

现在我想config.js在 Vi 中打开该文件。我的常规方法是:

$ vi path/to/directory/config.js

我必须在制表符补全的帮助下手动输入,或者从 grep 结果中突出显示文件名并复制/粘贴它。

但我希望能够通过指定它是 grep 命令中的第二个结果来 Vi 该文件。因此,类似这样的操作:

$ grep -Irl "foo" | xargs vi 2

显然 xargs 不会这样工作,这只是一个例子。但我试图找到是否有办法使用 xargs(或任何其他实用程序)来实现这一点,但我没有找到。

一位队友向我建议一起使用headtail,就像这样:

$ grep -Irl "foo" | tail -n 1 | xargs vi

将检索 task.js,并且

$ grep -Irl "foo" | head -n 2 | tail -n 1 | xargs vi

将检索 config.js。想知道是否有更简洁的方法。

答案1

怎么样

   vi $( grep -IrL "foo" | awk "NR==3" )

这使用 AWK 来查找适当的行。然后将输出用作 vi 的命令行参数。

我是老派的,所以我更喜欢同等的,但稍微不满意的版本-

 vi ` grep -IrL "foo" | awk "NR==3" `

答案2

这与要求的并不完全一致,因为它不使用管道进入 vi,而是使用sed

vi $( grep -Irl "foo" | sed -n '2 p')

答案3

为此,我编写了一个包装函数,如果您想重用命令的输出行,可以使用它。

首先是狂欢

catch() {
   out="$($@)" 
   nl <<< "$out"
   read -a r -d '\n' <<< "$out"
   r=("dummy" "${r[@]}")
}

然后对于

catch () {
   out="$($@)" 
   nl <<< "$out"
   r=("${(@f)out}") 
}

两种变体的用法相同。首先,运行所需的命令,并在前面加上抓住,它将以漂亮的编号形式显示命令的输出:

$ catch grep -Irl "foo"
   1  path/to/dir/task.js
   2  path/to/dir/help.js
   3  path/to/dir/config.js
$

现在,您可以使用数组参数重复使用以下命令中的任意行$r,例如

$ wc -c ${r[2]}
14044 path/to/dir/help.js

你可以省略花括号 ( wc -c $r[2]),但在狂欢不幸的是你需要它们。

我想到了一些注意事项:

  • 仅在命令完成后才显示输出
  • 输出中的奇怪字符可能会产生不稳定的行为(例如文件名中的换行符)
  • 仅捕获到 STDOUT 的输出(如果某些输出写入 STDERR,它将在控制台上分离并被忽略$r

相关内容