bash 腳本如何從管道寫入其標準輸出?

bash 腳本如何從管道寫入其標準輸出?

我有一個呼叫函數的 bash 腳本。除此之外,該函數執行一個接收其輸出的管道。為了簡化它,這是一個人為的例子:

#!/bin/bash
func() {
  ls "$@" | sort | rev > /tmp/output
}
func "$@"

然後你會做類似的事情來運行它。它會做它的事情並將其有效負載傳遞到文件。螢幕上沒有輸出。

$ ./myscript .

sort現在,假設我想要標準輸出的輸出。我該怎麼做呢?

我可以這樣實現:

ls "$@" | sort | tee /dev/tty | rev > /tmp/output

但是,使用/dev/tty是錯誤的,因為這是行不通的:

$ ./myscript > myfile

是否有更正確的方法來從函數內的管道內引用 bash 腳本的標準輸出?

(我在 Arch Linux 上使用 bash 4.3.0)

答案1

我能想到的最簡單的方法是:

ls "$@" | sort | tee >(rev > /tmp/output)

將向teeSTDOUT 發送一份副本,並且由於其後不再有 a |,因此這是繼承的,這意味著如果沒有重定向,它將轉到 TTY,myfile如果是,則將轉到您的 TTY。
另一個副本將發送到rev > /tmp/output其 STDIN。在 bash 中,>(...)運行括號之間的任何內容,然後將 替換>(...)為連接到其 STDIN 的管道的路徑。

答案2

由於另一個答案對此並不清楚,因此另一種(另一種)方法是

exec 3>&1
ls | sort | tee /dev/fd/3 | rev > /tmp/output

exec 3>&1 重複將檔案描述符 1 (stdout) 指定為檔案描述符tee /dev/fd/33 sort。這應該可以在任何 shell 中工作,但可能取決於作業系統。一個應該獨立於作業系統但bash特定於作業系統的變體是:

exec 3>&1
ls | sort | tee >( cat >&3 ) | rev > /tmp/output

在 中bash,為您提供一個指向正在執行的進程的管道的檔案句柄>(command)command。在任何 (?) shell 中,運行command >&fdcommand 其標準輸出重定向到指定的檔案描述符,該檔案描述符必須是先前建立的。

一個更複雜的版本,應該可以在任何 *nix (Posix) 系統上工作,是

pipe_to_stdout=$(mktemp -u)
mkfifo "$pipe_to_stdout"
cat "$pipe_to_stdout" &
ls | sort | tee "$pipe_to_stdout" | rev > /tmp/output
rm "$pipe_to_stdout"

這與第二個範例幾乎相同(cat從 fifo 讀取並寫入 stdout),但在 shell 層級使用較少的煙霧和鏡子。

請注意,這些答案是靈活的,因為您ls只需重新排列命令即可將 的輸出寫入標準輸出。

相關內容