sh shell:将输出重定向到终端和脚本内的文件

Abh*_*pta 8 shell logs io-redirection shell-script

如何从脚本内部将 stdout 和 stderr 重定向到文件和终端。

#!/bin/sh

LOG_FILE="/tmp/abc.log"

exec &> >(tee -a $LOG_FILE)

echo "Start"
echo "Hi" 1>&2 
echo "End"
Run Code Online (Sandbox Code Playgroud)

我找到了上面的脚本。但是这个脚本只适用于 bash。使用 sh shell 会出现以下错误:

./abc.sh: 5: Syntax error: redirection unexpected (expecting word)
Run Code Online (Sandbox Code Playgroud)

我想要一个同时适用于 sh 和 bash shell 的脚本。

Sté*_*las 10

是的,&>是一个bash运算符(现在也被 支持zsh,虽然zsh总是>&像 in 一样csh)和>(...)一个ksh运算符(现在也被zsh和支持bash),两者都不是sh运算符。那个未加引号的 $LOG_FILE 显然不希望在此处使用 split+glob,这使其成为 zsh 语法(唯一一种在未加引号的扩展中不隐式执行 split+glob 的 shell,尽管在 中zsh,您只需执行exec >&1 > $LOG_FILE 2>&1)。

sh语法上,您可以执行以下操作:

#! /bin/sh -
LOG_FILE="/tmp/abc.log"

{

  # your script here


} 2>&1 | tee -- "$LOG_FILE"
Run Code Online (Sandbox Code Playgroud)

或者把所有东西都放在一个函数中:

#! /bin/sh -
LOG_FILE="/tmp/abc.log"

main() {

  # your script here


}

main "$@" 2>&1 | tee -- "$LOG_FILE"
Run Code Online (Sandbox Code Playgroud)

在任何情况下,这种方法和您的zsh风格方法最终都会在与在 stdout 上打开的资源相同的资源上打印错误消息。因此,如果有人这样做your-script > out 2> err, ,err将是空的,并且out将包含正常输出和错误。

为确保保留输出和错误的原始目的地,您可以改为:

{
  {
    main "$@" 3>&- | tee -a -- "$LOG_FILE" >&3 3>&-
  } 2>&1 | tee -a -- "$LOG_FILE" >&2 3>&-
} 3> "$LOG_FILE" 3>&1
Run Code Online (Sandbox Code Playgroud)

(未经测试)。

  • @fra-san,这是截断文件(如果无法打开文件则中止命令)。然后两个“tee”再次以追加模式打开文件。 (2认同)