将输出重定向到 stdout 或文件(不是两者)

将输出重定向到 stdout 或文件(不是两者)

我想创建一个脚本,当以交互方式调用时,该脚本写入标准输出,但如果从另一个脚本调用并且变量 EVENT_LOGGER 由调用脚本定义,则写入文件 EVENT_LOGGER。

可能有一种简单的方法可以做到这一点,但我就是不知道。我当然可以将这个逻辑添加到生成输出的每个地方:

if [[ -f $EVENT_LOGGER ]]
then
   echo "Some message" >> $EVENT_LOGGER
else
   echo "Some message"
fi

但这会给脚本增加很多体积。

我希望我可以做这样的事情:

if [[ ! -f $EVENT_LOGGER ]]
then
   EVENT_LOGGER = "&1"
fi

那么,所有输出命令将是:

echo "Some message" >> $EVENT_LOGGER

他们会转到文件或标准输出,无论 EVENT_LOGGER 指向哪个。

那行不通。还有另一种方法可以让 $EVENT_LOGGER 解析为标准输出吗?

我在 AIX 7.1 上使用 ksh93

答案1

在许多 Unix 变体上,您可以通过文件名访问标准输出/dev/stdout,因此:

if [[ -z $EVENT_LOGGER ]]; then
  EVENT_LOGGER=/dev/stdout
fi
echo >>"$EVENT_LOGGER" 'This is a log message'

不过我不确定它是否可以在 AIX 上使用。看"> /dev/stdout" 的可移植性Unix 系统没有 /dev/stdin、/dev/stdout 和 /dev/stderr?

或者,将所有日志记录保留到标准输出,并可选择将标准输出重定向到文件。如果您调用exec不带命令名但带有重定向的内置函数,则会为脚本的其余部分设置重定向。

if [[ -n $EVENT_LOGGER ]]; then
  exec >>"$EVENT_LOGGER"
fi
echo 'This is a log message'

请注意,脚本调用的程序的输出将转到同一日志文件。如果您不想这样做,请在另一个文件描述符上进行日志记录。

if [[ -n $EVENT_LOGGER ]]; then
  exec 3>>"$EVENT_LOGGER"
else
  exec 3>&1
fi
echo >&3 'This is a log message'

另一种方法是根据需要以不同的方式定义函数。

if [[ -n $EVENT_LOGGER ]]; then
  log () {
    echo "$*" >>"$EVENT_LOGGER"
  }
else
  log () {
    echo "$*"
  }
fi
log 'This is a log message'

无论你做什么,我建议使用函数。这样,如果您想更改日志记录的工作方式(例如,记录到终端和文件、添加颜色、使其成为有条件的……),就会容易得多。

一些一般注意事项:

  • 该测试-f测试文件是否存在。这不是一个好的测试。相反,使用-n(-z测试它是否为空)来测试变量是否非空。
  • =在变量赋值中,不能在符号周围放置空格。

答案2

你要这个:

$ cat interactive.sh
#!/bin/bash
if [[ -n "$EVENT_LOGGER" ]]; then
    exec 1>>"$EVENT_LOGGER"
fi
date
echo "hello world"

神奇之处:exec 1>>"$EVENT_LOGGER"在脚本运行期间重定向标准输出。

演示:

  1. 变量未定义,输出到 stdout

    $ bash interactive.sh
    Sat Jan  6 19:06:02 EST 2018
    hello world
    
  2. 变量定义,输出到文件

    $ env EVENT_LOGGER="./event.logger" bash interactive.sh
    $ cat event.logger
    Sat Jan  6 19:06:13 EST 2018
    hello world
    

相关内容