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) 指定为文件描述符 3。然后将 的输出tee /dev/fd/3的副本写入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只需重新排列命令即可将 的输出写入标准输出。

相关内容