bash/sh/ash中外部程序为何意外干扰while循环的shell变量?
问题:while循环中调用ffmpeg会破坏read读取的变量(隔次迭代出错)
现象复现
在bash、sh或busybox ash的while循环里,用read -rd ''读取空分隔输入时,每次调用ffmpeg后,隔一次迭代就会出现变量损坏——变量开头会缺失几个字节,导致后续命令报错。
复现代码(替换test.mkv为有效视频路径):
#!/bin/bash while IFS= read -rd '' f;do ls -- "$f" ffmpeg -i "$f" -c copy -f matroska - &>/dev/null done < <(printf '%s\0' test.mkv{,,,})
错误输出示例:
test.mkv ls: cannot access '.mkv': No such file or directory test.mkv ls: cannot access 'st.mkv': No such file or directory
无论用进程替换还是外部管道(比如find -print0)传递输入,问题都会出现。
原因
核心问题是ffmpeg默认会读取标准输入(stdin),而while循环里的read正是从这个stdin读取输入数据的。当ffmpeg启动后,它会从stdin读取内容,吃掉了原本要交给下一次read的部分输入,导致read读取到不完整的字符串,最终变量$f损坏。
解决方案
方案1:让ffmpeg不读取stdin
给ffmpeg添加-nostdin参数,强制它不占用标准输入,这样就不会干扰read的读取流程:
#!/bin/bash while IFS= read -rd '' f;do ls -- "$f" ffmpeg -nostdin -i "$f" -c copy -f matroska - &>/dev/null done < <(printf '%s\0' test.mkv{,,,})
方案2:提前读取所有输入到数组
用readarray一次性把所有输入读入数组,再用for循环迭代。这种方法会消耗额外内存,但避免了ffmpeg对stdin的干扰:
#!/bin/bash readarray -d '' arr < <(printf '%s\0' test.mkv{,,,}) for f in "${arr[@]}";do ls -- "$f" ffmpeg -i "$f" -c copy -f matroska - &>/dev/null done
运行后输出正常:
test.mkv test.mkv test.mkv test.mkv
内容的提问来源于stack exchange,提问作者mossymountain
相关产品推荐
相关产品推荐

