管道進入另一個管道未按預期工作的結果
我是 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
這樣做更容易,雖然發現我在這裡提到的內容很有趣。
您的
echo "some message" | { echo "USER TTY" | xargs -o write; }
命令不能工作,因為它這樣做:
|-------------------------------------------| echo "some message" --+-> echo "USER TTY" --> xargs -o write; | |-------------------------------------------|
的標準輸入
xargs
是來自的管道echo "USER TTY"
。將echo "some message"
通過管道傳輸到復合命令{ echo "USER TTY" | xargs -o write; }
中,這實際上意味著將echo "some message"
通過管道傳輸到echo "USER TTY"
; 這意味著該write
命令看不到some message
.PS由於您已指定
-o
選項xargs
,write
的標準輸入設置為終端。如果您想說,這將起作用echo "USER TTY" | xargs -o write
然後只需鍵入消息,但它不會連接
write
到最外面的echo
.如果您有一些*
Command B
輸出USER
*和TTY
(但只有一對),您可以嘗試echo "一些資訊" | 寫 $(*命令 B* )
更新:*
Command B
*以下可能適用於僅輸出一對USER
and 的假設情況TTY
,但可能不適用於您的實際情況。閱讀它,然後再往下看討論。如果,如您所說,您使用的是 bash,並且您有 GNU
xargs
(Linux 上的標準;可能可用於其他類 Unix 作業系統),您也可以嘗試echo "一些資訊" | xargs -a <(*命令 B* ) 寫
正如 rici 在 從使用 xargs 執行的命令中讀取標準輸入中所建議的那樣。
我剛剛意識到您可能擁有 GNU
xargs
,因為-o
POSIX 未指定該選項。更多想法:
- 這可能會解決您的部分問題:副手,我想不出任何例子
*命令 A* | {*命令 B* | *命令 C* ; }
不同於
*命令 A* | *命令 B* | *命令 C*
即,分組產生影響的地方。我希望我忽略了一些明顯的事情,我期待有一個例子向我指出。同樣地,
{*命令 A* | *命令 B* ; } | *命令 C*
將是等效的。
- 管道如
*命令 A* | *命令 B* | *命令 C*
可能有用。作為一個簡單的例子:
$ echo GET | tr BEG VAC | od -cb 0000000 C A T \n 103 101 124 012 0000004
- 像這樣的管道
*命令 A* | *命令 B* | xargs *(選項)* *命令 Y*
如果您認為它是有用的
{*命令 A* | *命令 B* ; } | xargs *(選項)* *命令 Y*
即,提供輸入到 . 如果你認為它是
*Command A* | *Command B*``xargs
*命令 A* | {*命令 B* | xargs *(選項)* *命令 Y* ; }
即,
*Command B*
提供輸入xargs
和*Command A*
提供輸入*Command Y*
,由於上面討論的原因,它不起作用:沒有辦法在*Command A*
和 之間建立數據流*Command Y*
。
- 然而,
*命令 A* | xargs *(選項)* **-a <(***命令 B* **)** *命令 Y*
有問題的原因不同:
xargs
這裡的工作是*Command Y*
(可能)多次執行。但是沒有*Command A*
多次執行的機制,所以它不能提供*Command Y*
多次輸入。 如果你真的想執行多次,你可以這樣做*Command A* | *Command Y*
*命令 B* | xargs *(選項)* sh -c '*命令 A* | *命令 Y* ' sh
例如,
$ 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
了 3 次,因為秒數不同(07
和09
)11
。這將適用於您的情況。(請注意,在我上面的範例中,一次
*Command Y*
從*Command B*
兩個參數中獲取參數,就像您真正想要/需要做的那樣write
。)如果*Command B*
產生看起來像(例如,)的輸出,那麼您可以這樣做
*name1* *tty1* *name2* *tty2* *name3* *tty3* …``fred tty17 wilma tty42 barney ttyS23
*命令 B* | xargs -n2 *(可能是其他選項)* sh -c 'echo " *some message* " | 寫“$1”“$2”' sh
- 但是,如果您不需要多次執行
*Command A*
(在您的情況下, )(因為它每次都會產生相同的輸出),您可以利用這一事實,並執行一次,保存輸出:echo "some message"``*Command A*
回顯“*一些消息*”> tmpfile;\ *命令 B* | xargs -n2 *(可能是其他選項)* sh -c 'write "$1" "$2" < tmpfile' sh; \ rm tmp 文件
- 因此,上述解決方案避免了
*Command A*
多次執行,但它仍然為每個使用者執行一次 shell。這是不可取的。我沒有看到任何方法來處理這種情況,使用xargs
, 無需多次啟動 shell。(再次,我希望有人向我指出。)根本不使用 shell 就很難處理它*,* 因為xargs
只能處理“簡單”命令——沒有重定向(<
)或管道(|
)。 但是,我們可以在沒有 的情況下處理它xargs
,更有創意地使用 shell。假設每行*Command B*
產生一對輸出(例如,(newline) (newline) (newline) ),那麼您可以這樣做*namen* *ttyn*``fred tty17
wilma tty42
barney ttyS23
回顯“*一些消息*”> tmpfile;\ *命令 B* | 朗讀時;寫 "$u" "$t" < tmpfile; 完畢; \ rm tmp 文件
深入研究並解決問題中的幾個微點:
- 在
echo "*一些資訊*" | { 迴聲“*使用者* *TTY* ”| xargs -o 寫;}
外殼本身實際上並沒有忽略該部分*。* 但是,正如我在答案的第一部分中所描述的那樣,它實際上是通過管道將其導入元件中。並且 不讀取其標準輸入;因此,未處理。
echo "*some message*"``echo "*USER* *TTY*"``echo
message
- >
請注意
{ echo "USER TTY" | xargs -o write; }
並write USER TTY
做同樣的工作(顯然?我懷疑這裡有一個我不知道的區別)。好的,如果這還不清楚:兩個變體都
write
使用參數呼叫程序,USER
並且TTY
. 是一個簡單的命令,它不會修改其標準 I/O 流,而只是從現有的標準輸入中讀取。這可能是 tty、管道或文件。該 變體將’s stdin 重定向為 be ,因為這就是這樣做的。通常(如果您不指定 ),的標準輸入是要執行的命令的參數來源,因此無法訪問較大環境中的主流標準輸入(這將是 消息的來源for ) — 因此它不能做到這一點write *USER* *TTY*``xargs``write``/dev/tty``-o``-a``xargs``xargs``write
可用於執行程序的數據流。因此,如果您不指定-a
or-o
,xargs
則將執行程序的標準輸入設置為/dev/null
.
- 注意
*命令 B* | xargs -n2 -o 寫
會有點工作,但它需要您為每個使用者鍵入一次輸入消息,因為它
write
為每個使用者呼叫一次,而沒有任何方法在迭代之間保存消息。如果你想向不同的使用者發送不同的消息,理論上你 可以使用它,但這並不實用,因為它不會給你任何提示或回饋來告訴你正在與哪個使用者交談。