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

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

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

#!/bin/bash

LOG_FILE="/tmp/abc.log"

exec &> >(tee -a $LOG_FILE)

echo "Start"
echo "Hi" 1>&2 
echo "End"

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

./abc.sh: 5: Syntax error: redirection unexpected (expecting word)

我想要一个可以与 sh 和 bash shell 一起使用的脚本。

答案1

是的,&>是一个bash运算符(现在也被 所支持zsh,而zsh始终具有>&与 in 相同的功能csh),以及>(...)一个ksh运算符(现在也被zsh和支持bash),两者都不是sh运算符。那个不带引号的 $LOG_FILE ,你显然不想在这里 split+glob ,使它成为 zsh 语法(唯一一个 shell 中 split+glob 不会在不带引号的扩展上隐式执行,尽管在 中zsh,你只需这样做exec >&1 > $LOG_FILE 2>&1)。

sh语法上,你可以这样做:

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

{

  # your script here


} 2>&1 | tee -- "$LOG_FILE"

或者将所有内容放入一个函数中:

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

main() {

  # your script here


}

main "$@" 2>&1 | tee -- "$LOG_FILE"

无论如何,这种方法和您的zsh-style 方法最终都会在与标准输出上打开的相同资源上打印错误消息。因此,如果有人这样做your-script > out 2> errerr将会是空的并且out将包含正常输出和错误。

为了确保保留输出和错误的原始目的地,您可以这样做:

{
  {
    main "$@" 3>&- | tee -a -- "$LOG_FILE" >&3 3>&-
  } 2>&1 | tee -a -- "$LOG_FILE" >&2 3>&-
} 3> "$LOG_FILE" 3>&1

(未经测试)。

另请注意,从安全角度来看,在全局可写目录中使用具有固定名称的文件是/tmp不好的做法,因为其他一些用户可能会放置具有相同名称的恶意符号链接,这会导致您覆盖它指向的文件。

相关内容