使用bash命令的输出(带管道)作为另一个命令的参数

CDu*_*Duv 10 bash shell nested pipe command-line-arguments

我正在寻找一种方法来使用命令的输出(比如command1)作为另一个命令的参数(比如command2).

我在尝试grep输出who命令时遇到了这个问题,但是使用了另一组命令给出的模式(实际上是tty管道输出sed).

语境:

如果tty显示:

/dev/pts/5
Run Code Online (Sandbox Code Playgroud)

who显示:

root     pts/4        2012-01-15 16:01 (xxxx)
root     pts/5        2012-02-25 10:02 (yyyy)
root     pts/2        2012-03-09 12:03 (zzzz)
Run Code Online (Sandbox Code Playgroud)

目标:

我只想就行了(S)"PTS/5"所以我通过管道输送ttysed如下:

$ tty | sed 's/\/dev\///'
pts/5
Run Code Online (Sandbox Code Playgroud)

测试:

尝试的以下命令不起作用:

$ who | grep $(echo $(tty) | sed 's/\/dev\///')"
Run Code Online (Sandbox Code Playgroud)

可能的方法:

我发现以下工作正常:

$ eval "who | grep $(echo $(tty) | sed 's/\/dev\///')"
Run Code Online (Sandbox Code Playgroud)

但我确信eval可以避免使用.

作为最后的一个节点:我注意到"-m"参数给who了我我想要的东西(只获得who与当前用户链接的那一行).但我仍然很好奇如何将管道和命令嵌套组合起来......

gho*_*oti 10

通常使用xargs使一个命令的输出成为另一个命令的选项.例如:

$ cat command1
#!/bin/sh

echo "one"
echo "two"
echo "three"

$ cat command2
#!/bin/sh

printf '1 = %s\n' "$1"

$ ./command1 | xargs -n 1 ./command2
1 = one
1 = two
1 = three
$ 
Run Code Online (Sandbox Code Playgroud)

但是......虽然这是你的问题,但这并不是你真正想知道的.

如果您不介意将tty存储在变量中,可以使用bash变量修改来进行替换:

$ tty=`tty`; who | grep -w "${tty#/dev/}"
ghoti            pts/198  Mar  8 17:01 (:0.0)
Run Code Online (Sandbox Code Playgroud)

(你想要-w因为如果你在pts/6上你不应该看到pts/60的登录.)

您只能在变量中执行此操作,因为如果您尝试将tty命令放入管道,它会认为它不再与终端关联运行.

$ true | echo `tty | sed 's:/dev/::'`
not a tty
$ 
Run Code Online (Sandbox Code Playgroud)

请注意,到目前为止,此答案中没有任何内容特定于bash.由于您正在使用bash,另一种解决此问题的方法是使用进程替换.例如,虽然这不起作用:

$ who | grep "$(tty | sed 's:/dev/::')"
Run Code Online (Sandbox Code Playgroud)

这样做:

$ grep $(tty | sed 's:/dev/::') < <(who)
Run Code Online (Sandbox Code Playgroud)


Gor*_*son 6

@ Eduardo的答案是正确的(当我写这篇文章时,已经出现了几个其他好的答案),但我想解释原始命令失败的原因.像往常一样,set -x看看实际发生的事情非常有用:

$ set -x
$ who | grep $(echo $(tty) | sed 's/\/dev\///')
+ who
++ sed 's/\/dev\///'
+++ tty
++ echo not a tty
+ grep not a tty
grep: a: No such file or directory
grep: tty: No such file or directory
Run Code Online (Sandbox Code Playgroud)

在上面并没有完全明确,但正在发生的tty是输出"不是tty".这是因为它是输出输出的管道的一部分who,所以它的标准输入确实不是tty.这是其他人的答案工作的真正原因:他们tty离开了管道,所以它可以看到你的实际终端.

顺便说一句,您提出的命令基本上是正确的(管道问题除外),但不必要的复杂.不要使用echo $(tty),它基本上和刚才一样tty.


Edu*_*nec 5

你可以在不借助于Bash变量修改的情况下使用sed来做到这一点,尽管@ruakh指出这在单行版本中不起作用(没有用分号分隔命令).我要离开这第一个方法了,因为我认为有趣的是它不能在一行中起作用:

TTY=$(tty); who | grep "${TTY#/dev/}"
Run Code Online (Sandbox Code Playgroud)

首先将输出tty放入变量中,然后删除/dev/grep使用它的前导.但是,如果没有分号TTY不是由那一刻的bash环境确实变扩建/重整grep的.

这是一个可行的版本,因为它使用已修改的环境生成子shell(具有TTY):

TTY=$(tty) WHOLINE=$(who | grep "${TTY#/dev/}")
Run Code Online (Sandbox Code Playgroud)

结果留在了$WHOLINE.

  • 这不起作用:"$ {TTY#/ dev /}"`过早扩展.您需要将变量赋值作为单独的命令(使用换行符或`;`或`&&`或whatnot). (2认同)