如何在Bash中管道到“空对象”并保留MySQL交互性?
MySQL命令统一行执行方案
需求背景
现有Shell代码根据输出文件是否为/dev/stdout,决定是否通过sed将输出中的NULL转换为\N(适配LOAD DATA LOCAL INFILE):
if [[ "${outfile}" == '/dev/stdout' ]]; then "${mysql_cmd[@]}" <"${infile}" >"${outfile}" else "${mysql_cmd[@]}" <"${infile}" | sed -e 's|[[:<:]]NULL[[:>:]]|\\N|g' >"${outfile}" fi
希望改写为统一的单行形式:
"${mysql_cmd[@]}" <"${infile}" | "${transformer_cmd[@]}" >"${outfile}"
核心要求:
- 当
transformer_cmd为空(无需sed转换)时,MySQL必须保持交互性(可打开shell输入SQL) - 尝试过用
cat作为空transformer,但无法满足交互要求 - 避免让
transformer_cmd包含|(已确认该方式不可行,会被解析为MySQL参数)
可行实现方案
方案1:用exec作为空transformer(推荐)
根据输出文件动态设置transformer_cmd数组,空场景下用exec替换管道进程,直接保留MySQL的交互性:
# 初始化transformer命令数组 if [[ "${outfile}" == '/dev/stdout' ]]; then # 空转换时用exec,让mysql直接关联终端 transformer_cmd=(exec) else # 需要转换时设置sed命令 transformer_cmd=(sed -e 's|[[:<:]]NULL[[:>:]]|\\N|g') fi # 统一执行单行命令 "${mysql_cmd[@]}" <"${infile}" | "${transformer_cmd[@]}" >"${outfile}"
原理:当transformer_cmd为exec时,管道右侧的exec会直接替换自身进程为左侧MySQL的输出流,相当于跳过管道,MySQL的标准输入/输出直接绑定终端,完美保留交互性。
方案2:动态构建命令行(无管道场景)
利用Shell的参数扩展,动态决定是否添加管道和transformer命令,无需依赖特殊工具:
# 根据输出文件设置transformer命令 transformer_cmd=() if [[ "${outfile}" != '/dev/stdout' ]]; then transformer_cmd=(sed -e 's|[[:<:]]NULL[[:>:]]|\\N|g') fi # 动态构建并执行命令 eval "${mysql_cmd[*]}" '<"${infile}"' ${transformer_cmd:+| "${transformer_cmd[*]}"} '>"${outfile}"'
原理:${transformer_cmd:+| "${transformer_cmd[*]}"}会在transformer_cmd非空时展开为| "sed ...",空时则不生成管道部分,让MySQL直接与终端交互。使用eval是为了确保管道符号被正确解析为命令分隔符,而非MySQL参数。
注意事项
- 用
cat作为空transformer无法满足交互要求的原因:管道会将MySQL的标准输出重定向到cat,同时MySQL的标准输入被绑定到infile,无法接收终端输入。 - 方案1是最可靠的实现,完全避免了管道对交互性的破坏,且语法清晰易维护。
内容的提问来源于stack exchange,提问作者Noel Yap
相关产品推荐
相关产品推荐

