我的bash脚本包含许多mysqldump blabla > dump.sql,mysq balbla < dump.sql以便可以在试运行模式下运行它。
实际上,关键是创建一个功能run来运行我要求它执行的任何操作。
run echo 'hello world'
run mysqldump blabla > dump.sql
run mysql blabla < dump.sql
run ssh blabla
# etc
run() {
if [[ "$(printenv DRY_RUN)" = "yes" ]]
then
echo "${@}"
else
${@}
fi
}
Run Code Online (Sandbox Code Playgroud)
但是,这是行不通的:
run "mysqldump -uuser -ppass dbase > dump.sql"
Run Code Online (Sandbox Code Playgroud)
我收到此错误:
mysqldump:找不到表:">"
您应该使用"${@}"而不是${@}(如 with echo "${@}"),但这不是问题的原因。
原因是重定向发生在命令行解析的早期,在参数替换之前。因此,在将变量放入>命令行后,shell 不再查找>。
我在发布答案后注意到的一个重要点:通过类似的电话
run mysqldump blabla > dump.sql
Run Code Online (Sandbox Code Playgroud)
该函数run没有看到>和dump.sql。这可能不是您想要的,因为它会阻止您使用单个环境变量更改所有重定向,因为 的输出echo "${@}"也会被重定向到文件。因此,你应该使用类似的东西run --redirect dump.sql mysqldump blabla,见下文。
有两种可能:
坚持"$@"使用eval。当然,这可能会让您陷入引用的噩梦。您必须引用除 the 之外的所有内容,>以便 shell>在删除引用之前在命令行中看到一个空字符。
单独处理重定向:
run --redirect dump.sql mysqldump blabla
run() {
if [ "$1" == '--redirect' ]; then
shift
redirect_target="$1"
shift
else
redirect_target='/dev/stdout' # works at least with Linux
fi
if [[ "$(printenv DRY_RUN)" = "yes" ]]
then
echo "${@}"
else
"${@}" > "$redirect_target"
fi
}
Run Code Online (Sandbox Code Playgroud)
redirect_target='/dev/stdout'如果将 放在if [ "$1" == '--redirect' ]的else分支中,则可以避免if [[ "$(printenv DRY_RUN)" = "yes" ]]。
if [[ "$(printenv DRY_RUN)" = "yes" ]]
then
if [ "$1" == '--redirect' ]; then
# do not output "--redirect file"
shift
shift
fi
echo "${@}"
else
if [ "$1" == '--redirect' ]; then
shift
redirect_target="$1"
shift
"${@}" > "$redirect_target"
else
"${@}"
fi
fi
Run Code Online (Sandbox Code Playgroud)