私は、bashプログラミングが初めてで、パイプとグループ化されたコマンドを使用して複数の引数を渡す方法を理解しようとしたいくつかのコマンドを試している間に、この奇妙な動作を発見して混乱しました。私が望むことを達成する他の方法があることを知っていますが、なぜこれが起こるのかを理解しようとしています。
write
組み込み機能プログラムを使用して、SSHサーバーに接続されているユーザー(ユーザーIDをUSER、TTYをTTYと考える)にメッセージを送信しようとしています。
次のようにメッセージをうまく送信できますが、
$ echo "some message" | write USER TTY
ただし、USERとTTYを渡す別のパイプを使用しようとすると、メッセージは送信されません。
$ echo "some message" | { echo "USER TTY" | xargs -o write; }
結果を見ると、bashは最初の部分($ echo "some message"
)を無視し、コマンドの実行後にメッセージを要求するようです。
{ echo "USER TTY" | xargs -o write; }
そして同じことをすることに注意してくださいwrite USER TTY
(明らかに?ここには私が認識しない違いがあると思います)。
繰り返しますが、これを行うより簡単な方法があることを知っていますが、コマンドのグループ化、パイピング、および入力引数を関数に渡すという点でbashがどのように機能するかを理解したいと思います。この分野のご意見をいただきありがとうございます。
私が宿題を求めるのを疑う人のために、人々がこの仕事に興味を持っているのを見て嬉しいです。私は実際に私のSSHサーバーのすべてのユーザーにメッセージを送信するためにエイリアスを作成しようとしています。これはwall
簡単だと思いますが難しいです。面白いです。私がここで言及する内容を明確にするためです。
答え1
あなたの
echo "some message" | { echo "USER TTY" | xargs -o write; }
このコマンドは次のことを行うため、機能しません。
|-------------------------------------------|
echo "some message" --+-> echo "USER TTY" --> xargs -o write; |
|-------------------------------------------|
標準入力xargs
はから来るパイプですecho "USER TTY"
。 getsecho "some message"
は複合コマンドにパイプされます。これは { echo "USER TTY" | xargs -o write; }
実際にはgetsがコマンドecho "some message"
にパイプされていないecho "USER TTY"
ことを意味します。 PSオプションを指定したので、標準入力が端末に設定されます。言いたいならこれはうまくいくwrite
some message
-o
xargs
write
echo "USER TTY" | xargs -o write
write
その後、メッセージを入力すると、最も外側のメッセージにリンクされませんecho
。
少し持っていたらCommand B
出力USER
そして TTY
(しかしカップルのみ)試してみることができます
echo "任意のメッセージ"を書く $(コマンドB)
修正する:以下は、仮想状況に適用できます。Command B
ペアのみ出力 USER
そして TTY
しかし、実際の状況には適していない可能性があります。読んで、以下の議論を見てください。
あなたが言ったようにbashを使っていて、GNUxargs
(Linuxの標準、他のUnix系オペレーティングシステムでも利用可能)がある場合は、次のことを試すこともできます。echo "任意のメッセージ" xargs -a <(コマンドB)書くリッチが提案したとおり xargsを使用して実行されたコマンドのstdinから読み取る。
POSIXがそのオプションを指定していないxargs
ため、GNUがある可能性があることに気づきました。-o
その他のアイデア:
これは問題の一部を解決することができます。ところで、どんな例も考えられません。
コマンドA|コマンドB|CommandC;
とは違うコマンドA|コマンドB|CommandC
グループ化が違いを生むところがここです。私は明らかなことを見落としていることを願って、誰かが私に例を教えてくれることを期待しています。同様に、{コマンドA|コマンドB;CommandC
同等です。次のパイプ
コマンドA|コマンドB|CommandC
役に立つかもしれません。簡単な例を見てください:$ echo GET | tr BEG VAC | od -cb 0000000 C A T \n 103 101 124 012 0000004
このようなパイプ
コマンドA|コマンドB|パラメータ(オプション) コマンドY
役に立つと思ったら{コマンドA|コマンドB; } |パラメータ(オプション) コマンドY
つまり、入力を提供します。そうだと思うならCommand A | Command B
xargs
コマンドA |コマンドB|パラメータ(オプション) コマンドY;
つまり、Command B
に入力を提供し、xargs
にCommand A
入力を提供すると、上記の理由で動作しません。との間にデータフローを設定するCommand Y
方法はありません。Command A
Command Y
しかし、
コマンドA |パラメータ(オプション) -a <(コマンドB) コマンドY
さまざまな理由で問題が発生します。ここでは、ジョブは(潜在的に)複数回実行されますxargs
。Command Y
ただし、複数実行のメカニズムがないため、Command A
入力を複数回提供することはできません。Command Y
本当に何度も実行したい場合はこれを行うことができます
Command A | Command Y
コマンドB|パラメータ(オプション) シューさん」コマンドA|コマンドY'多様
例えば、$ echo S F u o n b | xargs -n2 sh -c 'date | tr "$1" "$2"; sleep 2' sh Fun, Mar 27, 2022 11:11:07 AM Son, Mar 27, 2022 11:11:09 AM Sub, Mar 27, 2022 11:11:11 AM
これは実行されます
date | tr S F date | tr u o date | tr n b
date
秒が異なるため(07
、、、09
)11
実際には3回実行されることがわかります。これはあなたの場合に動作します。 (上記の例では、
Command Y
実際に必要な/必要なものと同じように、両方のパラメータから同時にパラメータを取得します。)次のような出力を生成する場合(たとえば)、Command B
write
Command B
name1 tty1 name2 tty2 name3 tty3 …
fred tty17 wilma tty42 barney ttyS23
コマンドBxargs-n2 |(たぶん他のオプションがあるかもしれません) sh -c「エコ」いくつかのニュース" | 書き込み "$1" "$2"' sh
Command A
ただし、(あなたの場合)複数回実行する必要がない場合はecho "some message"
(毎回同じ出力が生成されるため)、これを利用してCommand A
一度実行して出力を保存できます。エコ」いくつかのニュース> tmpファイル コマンドBxargs-n2 |(たぶん他のオプションがあるかもしれません) sh -c '"$1" "$2" 書き込み < tmpfile' sh; rm 一時ファイル
したがって、上記の解決策は
Command A
複数の実行を防ぎますが、ユーザーごとに一度だけシェルを実行します。これは望ましくありません。xargs
シェルを何度も起動せずにこの状況を処理する方法はありません。 (誰かが指摘してくれることを期待する。) シェルを使わないと処理しにくい。それでも、xargs
「単純な」コマンドのみを処理できるため、リダイレクト(<
)やパイプ(|
)はありません。 しかし、、これを処理する代わりに、xargs
シェルをより創造的に使用できます。各行がCommand B
一対の出力を生成するとします(例:namen ttyn
fred tty17
(新しいチーム)wilma tty42
(新しいチーム)barney ttyS23
(新しいチーム) )それでできますエコ」いくつかのニュース> tmpファイル コマンドB|utを読み取るときに "$u" "$t" < tmpfile; rm 一時ファイル
質問のいくつかの重要な点を詳しく見て、解決してください。
存在する
エコ」いくつかのニュース"|{エコ"ユーザー テレタイピスト" | xargs -o 書き込み; }
シェルは実際にその部分を無視しません。echo "some message"
それ自体。 しかし、答えの最初の部分で説明したように、その部分に効果的にリンクされます。したがって、標準入力を読みません。echo "USER TTY"
echo
message
進まなかった。-
{ echo "USER TTY" | xargs -o write; }
そして同じことをすることに注意してくださいwrite USER TTY
(明らかに?ここには私が認識しない違いがあると思います)。いいですね。まだ明確ではない場合に備えて、両方のバリアントは
write
引数を使用してプログラムを呼び出します。USER
そしてTTY
。標準 I/O ストリームを変更せずに、単に既存の stdin から読み込む単純なコマンドです。これはtty、パイプ、またはファイルです。このバリアントはstdinをリダイレクトする役割を果たすため、stdinをリダイレクトします。通常、(指定されていない場合)stdinは実行されるコマンドの引数ソースであるため、より大きな環境では広く使用されているstdinにアクセスできません。write USER TTY
xargs
write
/dev/tty
-o
-a
xargs
xargs
情報forwrite
) - だから作成できませんそれ実行者が使用できるデータストリーム。したがって、-a
orを-o
指定しないと、xargs
ランチャーの標準入力がに設定されます/dev/null
。 気づく
コマンドB| xargs -n2 -o 書き込み
少し機能しますが、入力を入力する必要があります。情報write
繰り返しの間にメッセージを保存する方法がなくても、各ユーザーに対して一度呼び出されるため、各ユーザーに対して一度呼び出されます。あなた できる理論的には、複数のユーザーに異なるメッセージを送信したい場合は、このオプションを使用できますが、どのユーザーと話しているかについてのヒントやフィードバックを提供しないため、実用的ではありません。
答え2
最初のポイント
echo "<command arguments>" | command
パラメータを入力としてエコーしているため、これは使用できません。コマンド引数の入力を使用するには、xargsを「コンバータ」として使用して入力をコマンドライン引数に変換する必要があります。
xargs
シェル(bashなど)の一部ではない外部バイナリ。 xargsには複数のバージョンがありますが、-o
このフラグを持つバージョンはGNUユーザースペースにあります。通常、Linuxではman <command name>
。からWebバージョンマニュアル:
このマニュアルページには xargs の GNU バージョンが文書化されています。 xargsは、標準入力から次に区切られた項目を読み取ります。スペース(二重引用符、一重引用符、またはバックスラッシュで保護できます。) または 改行文字、初期引数を使用してコマンド(デフォルトはecho)を1回以上実行し、標準入力から読み取った項目を実行します。
xargsがすることは、入力をテーブルの行と同じフィールドに分割することです。各フィールドに対して、xargs(デフォルト)はシステム定義の制限まで引数をプログラムに渡します。スペースと改行文字を区切り文字(|
表など)として扱います。入力 "USER TTY" には USER と TTY の間にスペースがあるため、xargs は次のようなテーブル行のようなものを生成します。
ARG1 | ARG2 |
---|---|
ユーザー | テレタイピスト |
2番目のポイント
- コマンドを実行するたびにファイルをパイプするには、以下のように xargs を使用してファイルを実行コマンドにパイプします。ただし、これにより新しいシェルが開き、現在のセッションの環境変数を使用できなくなります。
echo "USER TTY" | xargs -I REPL sh -c 'echo "some message" | write REPL'
分析:
-I
フラグは、REPL
コマンドの実行時にフィールドに置き換えられるパラメーターを使用します。
ユーザー | テレタイピスト |
だからxargsが実行されます
sh -c 'echo "some message" | write USER TTY'