有条件地将命令的输出定向到 bash 中的 /dev/null

Conditionally directing a command's output to /dev/null in bash

我有以下 bash 脚本:

flag=false
command_name \
$(  flag == false  && printf %s '>/dev/null') 

我预计终端没有输出,但我还是得到了一些。如果我将输出重定向到与 command-name 在同一行的 /dev/null 而没有扩展,那么它会被抑制。

命令是来自 android SDK

的 dx 工具

编辑 1: 这里的代码来自脚本

dx \
    --dex \
    $( ( (( flag_v == 1 )) || (( flag_v == 'd' ))) && printf %s '--verbose') \
    --no-strict \
    --output="../"$app_name.jar \
    $(find . -type f -name '*.class') \
    $( $dexflag == false && printf %s '>/dev/null')

因为我 运行 这个工具和它按预期工作。我不认为它可能是一个错误流。

有条件地重定向标准输出

重定向是 shell 语法——它们必须在 参数扩展之前的解析阶段被识别,因此您不能通过变量扩展生成它们(不提交 evil)。

可以做的(在bash 4.1或更高版本中)是有一个无条件重定向,但是有它重定向到的东西 变化:

# Create an out_fd variable that points to stdout (FD 1) if dexflag != "false", or to a new
# handle on /dev/null otherwise
if [[ $dexflag = false ]]; then
  exec {out_fd}>/dev/null # maybe put 2>&1 as well to suppress stderr
else
  out_fd=1 # use FD 1 (stdout)
fi

# run dex with its stdout redirected to the FD number in "out_fd"
dex ... >&"$out_fd"

# if out_fd is not stdin/stdout/stderr, then go ahead and close it when done.
(( out_fd > 2 )) && exec {out_fd}>&-

注:

  • 字符串比较以 [[ $var = $pattern ]] 的形式进行(或 [[ $var = "$string" ]] 进行精确匹配)。参见 the bash-hackers' wiki on the conditional expression
  • 在 bash 4.1 或更高版本中,exec {fd_varname}>file 打开 file,并将指向该文件的文件描述符编号放入变量 fd_varnameexec {fd_varname}>&- 关闭编号存储在 fd_varname.
  • 中的文件描述符
  • 使用旧版本的 bash,您仍然可以执行此逻辑,但您需要手动分配一个未使用的 FD,而不是自动分配一个文件描述符编号不是 0、1 或 2 中任何一个的数字(为 stdin、stdout 和 stderr 保留)。因此,在那种情况下,if 分支中可能是 exec 3>/dev/nullexec 3>&1dex 命令中可能是 >&3exec 3>&- 到关闭它。

有条件地安全生成参数列表

请参阅 BashFAQ #50 进行长篇讨论。不过,简而言之:对于除重定向到 /dev/null 以外的所有内容,需要进行一个简单的更改以使其符合最佳实践:使用数组。

#!/bin/bash

args=( )

case $flag_v in
  1|d) args+=( --verbose ) ;;
esac

while IFS= read -r -d '' filename; do
  args+=( "$filename" )
done < <(find . -type f -name '*.class' -print0)

dx --dex --no-strict --output="../$app_name.jar" "${args[@]}"
  • 参见 BashPitfalls #1 describing why $(find ...) (like $(ls ...)) is unsafe, and Using Find 最佳实践。
  • 请参阅 BashFAQ #24 了解为什么使用 while read ...; do ...; done < <(find ...) 而不是 find ... | while read ...; do ...; done