如何在 (ba)sh 命令中 get/parse 重定向的 "target"

How to get/parse the "target" of a redirect in (ba)sh command

我必须通过模拟器 运行 二进制文件,但二进制文件是庞大而复杂的基准测试套件的一部分。那么在正常系统上会是这样的:

# First form
./binary -long=list -of=args <input.txt >std.out 2>std.err

需要看起来像这样:

# second form
simulator -c ./binary -o "-long=list -of=args" -i input.txt --output=std.out --errout=std.err 

基准测试套件正在传递命令,即在 (bash) 变量中带有所有内容(args 和重定向)的二进制文件,例如$CMD="./binary -long=list -of=args <input.txt >std.out 2>std.err",我需要找出所有重定向的目标(即示例中的 intpu.txtstd.outstd.err),以便我可以转换命令在第一种形式到第二种形式的命令)。

那么有没有办法,例如,告诉 bash 执行命令 $CMD,其中包含二进制文件、args 和重定向,并解析它,然后 return,比方说,什么是输入重定向(即 input.txt),或其他重定向之一(std.outstd.err)?

当然不用手动解析...

像这样:

$ CMD="./binary -long=list -of=args <input.txt >std.out 2>std.err"
$ bash -secret_option_to_parse_redirect_target=input "$CMD"
intpu.txt
$ bash -secret_option_to_parse_redirect_target=output "$CMD"
std.out
$ bash -secret_option_to_parse_redirect_target=error "$CMD"
std.err

如果您相信 cmd 可以解析为一个简单的命令,您可以使用 eval 添加一个包装器来读取命令行和主动重定向。在 https://replit.com/@CharlesDuffy2/GrouchyHelplessInformationtechnology#main.sh

处查看此代码 运行

请注意,这需要操作系统的 /proc/*/fd 接口与 Linux 提供的接口兼容。

read_fd() {
  local fd_num dest_var fd_dest default_val bash_pid=$BASHPID
  fd_num=; dest_var=; default_val=${3:-"/proc/self/fd/$fd_num"}
  printf -v "$dest_var" %s "$default_val"
  [[ -e /proc/$bash_pid/fd/$fd_nume ]] || return
  fd_dest="$(readlink "/proc/$bash_pid/fd/$fd_num")" || return
  [[ -e $fd_dest ]] || return
  printf -v "$dest_var" %s "$fd_dest"
}

parse_cmd() {
  read_fd 0 stdin_src
  read_fd 1 stdout_dest
  read_fd 2 stderr_dest
  argv_dest=( "$@" )
}

...用作:

# all-caps variable names are reserved; do not use them in your own code
cmd="./binary -long=list -of=args <input.txt >std.out 2>std.err"

# inputs need to exist for redirections to work
touch input.txt

eval "parse_cmd $cmd"
echo "stdout destination is $stdout_dest"
echo "stderr destination is $stderr_dest"
echo "stdin source is $stdin_src"
echo "argument list follows, one per line:"
printf ' - %q\n' "${argv_dest[@]}"
echo
echo "to run this, you could use:"
echo "${argv_dest[*]@Q} <$stdin_src >$stdout_dest 2>$stderr_dest"