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

前端 未结 4 1405
Happy的楠姐
Happy的楠姐 2020-12-06 02:17

I\'m looking for a way to use the ouput of a command (say command1) as an argument for another command (say command2).

I encountered this problem when trying to

相关标签:
4条回答
  • 2020-12-06 02:43

    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:

    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 not in the environment by the moment bash does the variable expansion/mangling for grep.

    Here's a version that does work because it spawns a subshell with the already modified environment (that has TTY):

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

    The result is left in $WHOLINE.

    0 讨论(0)
  • 2020-12-06 02:45

    One usually uses xargs to make the output of one command 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 ... 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=`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.)

    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.

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

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

    This does:

    $ grep $(tty | sed 's:/dev/::') < <(who)
    
    0 讨论(0)
  • 2020-12-06 02:46

    @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:

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

    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.

    0 讨论(0)
  • 2020-12-06 02:49

    You can do it like this:

    tid=$(tty | sed 's#/dev/##') && who | grep "$tid"
    
    0 讨论(0)
提交回复
热议问题