I have to run a binary through a simulator, but the binary is part of a huge and complicated benchmarking suite. So what on the normal system would look like this:
# First form
./binary -long=list -of=args <input.txt >std.out 2>std.err
needs to look like this:
# second form
simulator -c ./binary -o "-long=list -of=args" -i input.txt --output=std.out --errout=std.err
The benchmarking suit is passing around the command, i.e. the binary with all the stuff after it (args and redirects) in (bash) variables e.g. $CMD="./binary -long=list -of=args <input.txt >std.out 2>std.err"
, and I would need to find out what are the targets of all the redirects (i.e. intpu.txt
, std.out
and std.err
in the example) so I can convert the command in the first form to the command in the second form).
So is there a way to, for example, tell bash to take the command $CMD
, which contains the binary, the args and the redirects, and parse it, and then return, say, what was the input redirect (i.e. input.txt
), or one of the other redirects (std.out
or std.err
)?
Without manually doing the parsing of course...
Something like this:
$ 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
CodePudding user response:
If you trust your cmd
to parse to a single simple command, you can use eval
to add a wrapper around it that reads the command line and active redirections. See this code running at https://replit.com/@CharlesDuffy2/GrouchyHelplessInformationtechnology#main.sh
Note that this requires an operating system with a /proc/*/fd
interface compatible with that provided by Linux.
read_fd() {
local fd_num dest_var fd_dest default_val bash_pid=$BASHPID
fd_num=$1; dest_var=$2; 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=( "$@" )
}
...used as:
# 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"