使用 bash 命令(带管道)的输出作为另一个命令的参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9635705/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use output of bash command (with pipe) as a parameter for another command
提问by CDuv
I'm looking for a way to use the ouput of a command (say command1) as an argument for another command (say command2).
我正在寻找一种方法来使用命令(比如 command1)的输出作为另一个命令(比如 command2)的参数。
I encountered this problem when trying to grep
the output of who
command but using a pattern given by another set of command (actually tty
piped to sed
).
我在尝试grep
输出who
命令但使用另一组命令(实际上是通过tty
管道传输到sed
)给出的模式时遇到了这个问题。
Context:
语境:
If tty
displays:
如果tty
显示:
/dev/pts/5
And who
displays:
并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)
Goal:
目标:
I want only the line(s) regarding "pts/5"
So I piped tty
to sed
as follows:
我想只是关于“PTS / 5”所以我的管道线(S)tty
以sed
如下:
$ tty | sed 's/\/dev\///'
pts/5
Test:
测试:
The attempted following command doesn't work:
尝试的以下命令不起作用:
$ who | grep $(echo $(tty) | sed 's/\/dev\///')"
Possible solution:
可能的解决方案:
I've found out that the following works just fine:
我发现以下工作正常:
$ eval "who | grep $(echo $(tty) | sed 's/\/dev\///')"
But I'm sure the use of eval
could be avoided.
但我确信eval
可以避免使用。
As a final side node: I've noticed that the "-m" argument to who
gives me exactly what I want (get only the line of who
that is linked to current user). But I'm still curious on how I could make this combination of pipes and command nesting to work...
作为最后一个边节点:我注意到“-m”参数给who
了我我想要的东西(只获取who
链接到当前用户的那一行)。但是我仍然很好奇如何使管道和命令嵌套的这种组合起作用......
采纳答案by Eduardo Ivanec
You can do this without resorting to sed with the help of Bash variable mangling, although as @ruakh points out this won't work in the single line version (without the semicolon separating the commands). I'm leaving this first approach up because I think it's interesting that it doesn't work in a single line:
您可以在Bash 变量 mangling的帮助下无需求助于 sed 就可以做到这一点,尽管正如@ruakh 指出的那样,这在单行版本中不起作用(没有分号分隔命令)。我将保留第一种方法,因为我认为有趣的是它不能在一行中工作:
TTY=$(tty); who | grep "${TTY#/dev/}"
This first puts the output of tty
into a variable, then erases the leading /dev/
on grep's use of it. But without the semicolon TTY
is notin the environment by the moment bash does the variable expansion/mangling for grep.
这首先将 的输出tty
放入一个变量中,然后擦除/dev/
grep 使用它的前导。但是,如果没有分号TTY
是不是由那一刻的bash环境确实变扩建/重整grep的。
Here's a version that does work because it spawns a subshell with the already modified environment (that has TTY
):
这是一个确实有效的版本,因为它生成了一个具有已修改环境(具有TTY
)的子shell :
TTY=$(tty) WHOLINE=$(who | grep "${TTY#/dev/}")
The result is left in $WHOLINE
.
结果留在$WHOLINE
.
回答by ghoti
One usually uses xargsto make the output of one command an option to another command. For example:
通常使用xargs使一个命令的输出成为另一个命令的选项。例如:
$ cat command1
#!/bin/sh
echo "one"
echo "two"
echo "three"
$ cat command2
#!/bin/sh
printf '1 = %s\n' ""
$ ./command1 | xargs -n 1 ./command2
1 = one
1 = two
1 = three
$
But ... while that was your question, it's not what you really want to know.
但是......虽然这是你的问题,但这并不是你真正想知道的。
If you don't mind storing your tty in a variable, you can use bash variable mangling to do your substitution:
如果您不介意将 tty 存储在变量中,则可以使用 bash variable mangling 进行替换:
$ tty=`tty`; who | grep -w "${tty#/dev/}"
ghoti pts/198 Mar 8 17:01 (:0.0)
(You want the -w because if you're on pts/6 you shouldn't see pts/60's logins.)
(你想要 -w 因为如果你在 pts/6 上,你不应该看到 pts/60 的登录。)
You're limited to doing this in a variable, because if you try to put the tty
command into a pipe, it thinks that it's not running associated with a terminal anymore.
您只能在变量中执行此操作,因为如果您尝试将tty
命令放入管道中,它会认为它不再与终端关联运行。
$ true | echo `tty | sed 's:/dev/::'`
not a tty
$
Note that nothing in this answer so far is specific to bash. Since you're using bash, another way around this problem is to use process substitution. For example, while this does not work:
请注意,到目前为止,此答案中没有任何内容特定于 bash。由于您使用的是 bash,因此解决此问题的另一种方法是使用进程替换。例如,虽然这不起作用:
$ who | grep "$(tty | sed 's:/dev/::')"
This does:
这样做:
$ grep $(tty | sed 's:/dev/::') < <(who)
回答by Gordon Davisson
@Eduardo's answer is correct (and as I was writing this, a couple of other good answers have appeared), but I'd like to explain why the original command is failing. As usual, set -x
is very useful to see what's actually happening:
@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
It's not completely explicit in the above, but what's happening is that tty
is outputting "not a tty". This is because it's part of the pipeline being fed the output of who
, so its stdin is indeed not a tty. This is the real reason everyone else's answers work: they get tty
out of the pipeline, so it can see your actual terminal.
上面的内容并不完全明确,但发生的事情tty
是输出“不是 tty”。这是因为它是被馈送输出的管道的一部分who
,所以它的标准输入确实不是一个 tty。这就是其他人的答案有效的真正原因:他们tty
退出管道,因此它可以看到您的实际终端。
BTW, your proposed command is basically correct (except for the pipeline issue), but unnecessarily complex. Don't use echo $(tty)
, it's essentially the same as just tty
.
顺便说一句,您提出的命令基本上是正确的(管道问题除外),但不必要地复杂。不要使用echo $(tty)
,它本质上与 just 相同tty
。
回答by anubhava
You can do it like this:
你可以这样做:
tid=$(tty | sed 's#/dev/##') && who | grep "$tid"