web-dev-qa-db-ja.com

別のコマンドのパラメーターとしてbashコマンド(パイプ付き)の出力を使用する

コマンドの出力(たとえばcommand1)を別のコマンド(たとえばcommand2)の引数として使用する方法を探しています。

grepコマンドの出力をwhoしようとしたが、別のコマンドセット(実際にはttysedにパイプされた)によって与えられたパターンを使用したときに、この問題が発生しました。

環境:

ttyが表示される場合:

/dev/pts/5

そして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)

ゴール:

「pts/5」に関する行だけが必要なので、次のようにttysedにパイプしました。

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

テスト:

試行された次のコマンドは機能しません:

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

考えられる解決策:

私は次のことがうまく機能することを発見しました:

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

ただし、evalの使用は回避できると確信しています。

最後のサイドノードとして:whoの「-m」引数が私が望むものを正確に与えることに気づきました(現在のユーザーにリンクされているwhoの行のみを取得します)。しかし、パイプとコマンドのネストのこの組み合わせを機能させる方法については、まだ興味があります...

11
CDuv

Bash変数のマングリング の助けを借りてsedに頼らずにこれを行うことができますが、@ ruakhが指摘しているように、これは1行バージョンでは機能しません(コマンドをセミコロンで区切ることなく)。この最初のアプローチは、1行で機能しないのは興味深いと思うので、そのままにしておきます。

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

これは、最初にttyの出力を変数に入れ、次にgrepがそれを使用するときに先頭の/dev/を消去します。しかし、セミコロンがないと、bashがgrepの変数展開/マングリングを実行する瞬間までに、TTYnotになります。

これは、すでに変更された環境(TTYがある)でサブシェルを生成するために機能するバージョンです。

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

結果は$WHOLINEに残されます。

5
Eduardo Ivanec

通常、 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
$ 

しかし...それはあなたの質問でしたが、それはあなたが本当に知りたいことではありません。

Ttyを変数に格納してもかまわない場合は、bash変数マングリングを使用して置換を行うことができます。

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

(pts/6を使用している場合、pts/60のログインは表示されないため、-wが必要です。)

ttyコマンドをパイプに入れようとすると、端末に関連付けられて実行されていないと見なされるため、これは変数での実行に制限されます。

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

これまでのところ、この回答にはbashに固有のものはないことに注意してください。 bashを使用しているので、この問題を回避する別の方法は、プロセス置換を使用することです。たとえば、これは機能しませんが、次のようになります。

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

これは行います:

$ grep $(tty | sed 's:/dev/::') < <(who)
10
ghoti

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

上記では完全に明示的ではありませんが、ttyが「ttyではない」を出力していることが起こっています。これは、パイプラインの一部であり、whoの出力が供給されているため、そのstdinは実際にはttyではありません。これが、他のすべての回答が機能する本当の理由です。パイプラインからttyを取得するため、実際の端末を確認できます。

ところで、提案されたコマンドは基本的に正しいですが(パイプラインの問題を除く)、不必要に複雑です。 echo $(tty)は使用しないでください。基本的にはttyと同じです。

6
Gordon Davisson

あなたはこのようにそれを行うことができます:

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