在 bash 中回显标准输出或文件的优雅解决方案

在 bash 中回显标准输出或文件的优雅解决方案

我有一个 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

我试图让变量$outfile等于stdout、 to &1,也许还有其他东西,但它只会写入具有该名称的文件,而不是实际写入标准输出。有更优雅的解决方案吗?

(*) 我可以作弊并用于stderr此目的,但我认为这也很丑陋,不是吗?

答案1

首先,你应该避免echo输出任意数据

在基于 Linux 的系统以外的系统上,您可以使用:

logfile=/dev/stdout

对于 Linux,这适用于某些类型的 stdout,但当 stdout 是套接字时会失败,或者更糟糕的是,如果 stdout 是常规文件,则会截断该文件,而不是在 stdout 在文件中的当前位置写入。

除此之外,在类似 Bourne 的 shell 中,没有办法有条件的重定向,尽管您可以使用eval

eval 'printf "%s\n" "$buf" '${logfile:+'> "$logfile"'}

代替多变的,你可以使用专用的文件描述符

exec 3>&1
[ -z "$logfile" ] || exec 3> "$logfile"

 printf '%s\n' "$buf" >&3

这样做的一个(小)缺点是,除了 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"

答案2

  1. 设置。outfile"/dev/stdout"
  2. 让用户选择文件名、覆盖outfile或保留默认值。
  3. printf '%s\n' "$outbuf" >"$outfile"

我使用是printf因为“为什么 printf 比 echo 更好?”。

有关此解决方案的注意事项,请参阅斯特凡·查泽拉斯的回答

答案3

尝试这个

#!/bin/bash
TOSCREEN="1" # empty OR 0 to log to file
if [[ ! -z "$TOSCREEN" && $TOSCREEN == "1" ]]; then
    echo "$outbuf"    # Write output buffer to the screen (stdout)
else
    if [[ ! -f $outfile ]]; then
      #echo -e "Making file "
      touch "$outfile"
    fi  
    echo "$outbuf" >> $outfile  # Write output buffer to file
fi

答案4

#!/bin/bash -ue

function stdout_or_file()
{
    DUMP_FILE=${1:-}

    if [ -z "${DUMP_FILE}" ]; then
        # print stdin to stdout
        cat
    else
        # dump stdin to a file
        sed -n "w ${DUMP_FILE}"
    fi
}

echo "foo" | stdout_or_file "${outfile}"

请注意,这${1:-}是特定于 bash 的,并且在“-u”模式下特别有用。甚至可以在其他 shell 中工作的通用单行可能是

echo "foo" | if [ -z "${outfile}" ]; then cat; else sed -n "w ${outfile}"; fi

相关内容