Bre*_*lad 4 bash shell-script stdout
我有一个 bash 应用程序正在产生一些结果,我想将结果回显stdout
到用户选择的文件中。因为我还向屏幕回显了其他交互式消息,所以要求用户>
在他想将结果回显到文件时明确使用重定向不是一个选项 (*),因为这些消息也会出现在文件中。
现在我有一个解决方案,但它很难看。
if [ -z $outfile ]
then
echo "$outbuf" # Write output buffer to the screen (stdout)
else
echo "$outbuf" > $outfile # Write output buffer to file
fi
Run Code Online (Sandbox Code Playgroud)
我试图让变量$outfile
等于stdout
, to&1
或者其他东西,但它只会写入具有该名称的文件,而不是实际写入标准输出。有没有更优雅的解决方案?
(*) 我可以作弊并stderr
为此目的使用,但我认为它也很丑陋,不是吗?
首先,您应该避免echo
输出任意数据。
在基于 Linux 的系统以外的系统上,您可以使用:
logfile=/dev/stdout
Run Code Online (Sandbox Code Playgroud)
对于 Linux,这适用于某些类型的 stdout,但是当 stdout 是套接字时会失败,或者更糟的是,如果 stdout 是常规文件,则会截断该文件,而不是在 stdout 在文件中的当前位置写入。
除此之外,在类似 Bourne 的 shell 中,无法进行条件重定向,但您可以使用eval
:
eval 'printf "%s\n" "$buf" '${logfile:+'> "$logfile"'}
Run Code Online (Sandbox Code Playgroud)
您可以使用专用文件描述符代替变量:
exec 3>&1
[ -z "$logfile" ] || exec 3> "$logfile"
printf '%s\n' "$buf" >&3
Run Code Online (Sandbox Code Playgroud)
这样做的一个(小)缺点是,除了 in 之外ksh
,fd 3 会泄露给脚本中运行的每个命令。使用zsh
,您可以sysopen -wu 3 -o cloexec -- "$logfile" || exit
代替exec 3> "$logfile"
但bash
没有等效项。
另一个常见的习惯用法是使用如下函数:
log() {
if [ -n "$logfile" ]; then
printf '%s\n' "$@" >> "$logfile"
else
printf '%s\n' "$@"
fi
}
log "$buf"
Run Code Online (Sandbox Code Playgroud)
outfile
为"/dev/stdout"
。outfile
或保留默认值。printf '%s\n' "$outbuf" >"$outfile"
我使用printf
是因为“为什么 printf 比 echo 好? ”。
有关此解决方案的注意事项,请参阅Stéphane Chazelas 的回答。