Bash中如何存储stdin/stdout文件句柄到变量?报错求解
问题描述
编写了如下bash脚本:
STDIN='&0' if some-condition; then STDIN=some-filename fi run-command <${STDIN}
运行时出现错误:&0: No such file or directory,针对STDOUT也存在类似问题,尝试过eval但未解决,请问如何修改才能让脚本正常运行?
解决方案
bash中,重定向里的&0(或&1)是文件描述符引用,属于shell语法元素,不能当作普通文件名赋值给变量后再用于重定向——shell会把它当成普通字符串去查找对应文件,这就是报错的原因。以下是几种可行的修改方式:
方式一:直接通过条件分支处理重定向
这是最直观且安全的写法,直接在不同条件下执行带对应重定向的命令:
处理STDIN的情况
if some-condition; then run-command < some-filename else run-command # 默认就从stdin读取,无需额外写<&0 fi
如果明确要显式指定从stdin读取,也可以写run-command <&0,效果和默认一致。
处理STDOUT的情况
if some-condition; then run-command > some-filename else run-command >&1 # 或者直接run-command,默认输出到stdout fi
方式二:用exec复用文件描述符(适合多次使用同一输入/输出源)
如果脚本中需要多次使用这个输入/输出源,可以用exec复制文件描述符,后续命令统一引用该描述符:
处理STDIN的情况
# 复制目标输入到文件描述符3 if some-condition; then exec 3< some-filename else exec 3<&0 # 复制stdin到fd3 fi # 后续所有需要用该输入的命令都可以用<&3 run-command <&3 # another-command <&3 exec 3<&- # 用完后关闭文件描述符3
处理STDOUT的情况
# 复制目标输出到文件描述符3 if some-condition; then exec 3> some-filename else exec 3>&1 # 复制stdout到fd3 fi # 后续所有需要用该输出的命令都可以用>&3 run-command >&3 # another-command >&3 exec 3>&- # 用完后关闭文件描述符3
方式三:使用eval(需注意安全风险)
如果一定要通过变量控制重定向,需要把完整的重定向表达式存在变量中,再用eval执行——之前的错误是因为只存了&0,没有包含重定向符号:
处理STDIN的情况
STDIN_REDIRECT="" if some-condition; then STDIN_REDIRECT="< some-filename" fi eval "run-command ${STDIN_REDIRECT}"
处理STDOUT的情况
STDOUT_REDIRECT="" if some-condition; then STDOUT_REDIRECT="> some-filename" fi eval "run-command ${STDOUT_REDIRECT}"
⚠️ 注意:eval存在安全风险,如果文件名包含空格、特殊字符(如$、*),可能导致意外执行恶意代码,因此优先推荐前两种方式。
内容的提问来源于stack exchange,提问作者Noel Yap
相关产品推荐
相关产品推荐

