Use bash command output (with pipe) as parameter for another command

I am looking for a way to use the output of a command (e.g. command1) as an argument for another command (e.g. command2).

I ran into this problem when trying to grep output of the who command, but using a template given by a different set of commands (actually tty with sed number).

Context:

If tty displays:

 /dev/pts/5 

And who displays:

 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) 

Purpose:

I want only lines (lines) relative to "pts / 5" Therefore, I passed tty to sed as follows:

 $ tty | sed 's/\/dev\///' pts/5 

Test:

Attempting the following command does not work:

 $ who | grep $(echo $(tty) | sed 's/\/dev\///')" 

Possible Solution:

I found out that the following works perfectly:

 $ eval "who | grep $(echo $(tty) | sed 's/\/dev\///')" 

But I am sure that the use of eval could be avoided.

As the last side of node: I noticed that the “-m” argument for who gives me exactly what I want (get only the who string that is associated with the current user). But I'm still wondering how I could use this combination of pipes and nested command commands ...

+8
bash shell command-line-arguments pipe nested
source share
4 answers

You can do this without resorting to sed using the Bash variable mangling , although as @ruah points out, this will not work in the single-line version (without a semicolon separating the commands). I leave this first approach because it seems interesting to me that it does not work on one line:

 TTY=$(tty); who | grep "${TTY#/dev/}" 

This first puts the tty output in a variable, and then erases the leading /dev/ when using grep. But without a semicolon, tty not in the environment by the time of bash whether / mangling for grep is being changed.

Here's the version that works because it spawns a subshell with an already changed environment (which has tty ):

 TTY=$(tty) WHOLINE=$(who | grep "${TTY#/dev/}") 

The result remains in $WHOLINE .

+5
source share

Usually, xargs is used to output one command as an option to another command. For example:

 $ 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 $ 

But ... as long as it was your question, this is not what you really want to know.

If you don't mind storing your tty in a variable, you can use the change bash variable for your substitution:

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

(You want to use -w because if you are on pts / 6 you should not see pts / 60 logins.)

You are limited to this in the variable, because if you try to put the tty command in a channel, it thinks that it no longer works with the terminal.

 $ true | echo `tty | sed 's:/dev/::'` not a tty $ 

Note that nothing in this answer yet applies to bash. Since you are using bash, another way to solve this problem is to use process substitution. For example, while this does not work:

 $ who | grep "$(tty | sed 's:/dev/::')" 

It does:

 $ grep $(tty | sed 's:/dev/::') < <(who) 
+6
source share

@Eduardo's answer is correct (and as I wrote this, some more good answers came up), but I would like to explain why the original team fails. As usual, set -x very useful to see what is actually happening:

 $ 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 is not completely explicit in the above, but what happens is that tty prints "not tty". This is due to the fact that part of the pipeline is fed to who output, so its stdin is really not tty. This is the real reason that everyone else is responding to the job: they get tty from the pipeline, so it can see your actual terminal.

By the way, your proposed command is mostly correct (with the exception of the pipeline problem), but unnecessarily complicated. Do not use echo $(tty) , it is essentially the same as tty only.

+5
source share

You can do it as follows:

 tid=$(tty | sed 's#/dev/##') && who | grep "$tid" 
+2
source share

All Articles