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

Har*_*hiv 1 bash terminal output-redirect

我有以下 bash 脚本:

flag=false
command_name \
$(  flag == false  && printf %s '>/dev/null') 
Run Code Online (Sandbox Code Playgroud)

我希望终端没有输出,但我仍然得到一些。如果我将输出重定向到没有扩展/dev/null的同一行command-name,那么它会被抑制。

命令是来自 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')
Run Code Online (Sandbox Code Playgroud)

当我运行该工具时,它按预期工作。我不认为这可能是一个错误流。

Cha*_*ffy 7

有条件地重定向标准输出

重定向是 shell 语法——它们必须参数扩展之前的解析阶段被识别,所以你不能通过变量扩展来生成它们(不作恶)。

可以做的(在 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}>&-
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 字符串比较在表单中完成[[ $var = $pattern ]](或[[ $var = "$string" ]]进行精确匹配)。有关条件表达式,请参阅bash-hackers 的 wiki
  • 在 bash 4.1 或更高版本中,exec {fd_varname}>file打开file并将指向该文件的文件描述符编号放入变量fd_varname. exec {fd_varname}>&-关闭其编号存储在fd_varname.
  • 使用旧版本的 bash,您仍然可以执行此逻辑,但不是自动分配文件描述符编号,而是需要手动分配,手动分配一个其他未使用的 FD 编号,该编号不是 0 中的任何一个, 1 或 2(为 stdin、stdout 和 stderr 保留)。因此,在这种情况下,它可能会exec 3>/dev/nullexec 3>&1if分支中,>&3dex命令上,并exec 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[@]}"
Run Code Online (Sandbox Code Playgroud)
  • 请参阅BashPitfalls #1描述为什么$(find ...)(如$(ls ...))不安全,以及使用 Find进入最佳实践。
  • 请参阅BashFAQ #24以了解为什么while read ...; do ...; done < <(find ...)使用find ... | while read ...; do ...; done.