如何控制作为参数之一传递给bash函数的重定向运算符



我正在尝试编写一些长时间/重复的配置&bash中的构建操作。从一个函数开始,该函数显示给定的命令加参数,然后用给定的参数执行它。功能定义如下:

runit () {
cmd=${@}
echo "${cmd}"
${cmd}
}
runit touch /tmp/cltconf1

上面(不涉及重定向操作符(显示命令并按预期触摸目标文件。

runit echo "gEnableSecureClient=True" > clt1.conf

以上(涉及重定向操作符(执行前不显示命令,执行后clt1.conf文件的内容为:

echo gEnableSecureClient=True
gEnableSecureClient=True

我可以理解重定向没有受到控制,因此导致echo${cmd}实际将内容echo gEnableSecureClient=True写入clt1.conf,然后实际执行命令然后写入内容gEnableSecureClient=True

我想知道这个重定向操作符是否可以根据我的要求进行控制。任何商店盗窃或逃跑顺序处理都会有所帮助。

您的问题是:

如何控制作为参数之一传递给bash函数的重定向运算符?

发明你自己的发明,并使用它将上下文(要重定向到的文件名(传递给你的函数。您可以使用全局变量,也可以使用一些很少使用的参数样式的位置参数,例如++,例如:

runit() {
# parse arguments - detect `++` followed by `>` and filename
local cmd
while (($#)); do
case "$1" in
"++") break; ;;
*) cmd+=("$1"); ;;
esac
shift
done
local outf=/dev/stdout
if (($#)) && [[ "$1" == "++" ]]; then
shift
while (($#)); do
case "$1" in
">") outf=$2; shift; ;;
*) echo "ERROR: Invalid arguments: expected >" >&2; return 1; ;;
esac
shift
done
fi
if (($#)); then
echo "ERROR: internal error when parsing arguments" >&2; return 1
fi
echo "Running ${cmd[*]} > $outf"
"${cmd[@]}" > "$outf"
}

runit echo "gEnableSecureClient=True" ++ '>' clt1.conf

或者使用全局var的例子,更简单,但更spagetti:

runit() {
if [[ -n "${runit_outf:-}" ]]; then     
echo "$* > $runit_outf" 
"$@" > "$runit_outf"
runit_outf=  # let's clear it after use
else
echo "$*"
"$@"
fi
}
# outputs to stdout
runit echo 123     
runit_outf=clt1.conf  # spaghetti code
runit echo 123        # outputs to file

这只是一个模板代码,我没有测试,已经在StackOverflow中编写。它不会处理文件描述符——为此,您可以编写自己的逻辑来解析表达式——即在>&1中检测&,或者编写非常不安全的代码并调用eval

上面给出的方法是,无论如何都不推荐,相反,我永远不会写这样的代码,并且强烈反对写这样复杂的逻辑来处理简单的情况。相反,您应该将命令的输出与命令的日志流区分开来,通常您会:

runit() {
local cmd
cmd=("$@")
echo "${cmd[*]}" >&2
"${cmd[@]}"
}

或者在代码中使用预先打开的专用文件描述符,或者根据情况将输出重定向到/dev/tty

在继续之前,您应该明确研究什么是bash数组以及何时使用bash数组,研究分词和文件名扩展,并使用https://shellcheck.net。当传递带有空格和特殊字符(如*?(的参数时,您现在的函数会以惊人的方式中断。