macOS下Bash脚本执行出现意外无限循环问题求助
我尝试运行一段Bash脚本,用于合并文件夹及子文件夹中所有文本文件的内容并输出到一个文本文件,脚本内容如下:
#!/bin/bash find . -type f -name '*.txt' -exec cat {} + >> output.txt
但该脚本出现了无限循环。
我的测试目录结构为:~/desktop/Dir0/Dir1/Dir2
我创建了两个文本文件:
- 在
~/desktop/Dir0/Dir1执行:touch text1.txt && echo "Hello" >> text1.txt - 在
~/desktop/Dir0/Dir1/Dir2执行:touch text2.txt && echo "World" >> text2.txt
随后我在Dir0目录内运行了该脚本。脚本始终无法结束,运行cat output.txt可见文件中无限重复Hello\nWorld\nHello\nWorld\nHello\nWorld...内容。
我已尝试的排查步骤:
- 在Mint虚拟机中运行同一脚本,可正常工作。
- 将Bash从3.2版本升级至5.1.16,问题仍存在。
- 查阅资料并进行测试。
请问有人知道可能是什么原因导致的吗?
核心原因
脚本执行时,>> output.txt会在当前目录(Dir0)创建output.txt文件,而find . -name '*.txt'会递归查找所有.txt文件,包括刚创建的output.txt。当find收集到这个新文件后,会再次执行cat把它的内容追加到自身,导致无限循环:
- 初始
find找到text1.txt和text2.txt,执行cat将内容写入output.txt output.txt被创建后,后续的find迭代会把它也纳入目标文件列表cat output.txt会把现有内容(Hello\nWorld)再次追加到output.txt,文件不断变大,循环往复
解决办法
有几种方式可以避免这个问题:
将输出文件放在查找范围之外
比如把output.txt放到上级目录:find . -type f -name '*.txt' -exec cat {} + >> ../output.txt在
find命令中排除输出文件
使用! -name参数排除output.txt:find . -type f -name '*.txt' ! -name 'output.txt' -exec cat {} + >> output.txt先收集所有文件再执行
cat
用变量存储找到的文件列表,再一次性合并,避免find过程中捕获新创建的文件:#!/bin/bash files=$(find . -type f -name '*.txt') cat $files >> output.txt注意:如果文件名包含空格,这种方式可能有问题,更稳妥的写法是用数组:
#!/bin/bash mapfile -t files < <(find . -type f -name '*.txt') cat "${files[@]}" >> output.txt
另外,你提到在Mint虚拟机中脚本正常工作,可能是因为该环境下find的实现或文件系统特性导致它没有重复扫描到新创建的output.txt,但这属于特殊情况,标准场景下必须考虑排除输出文件或移出查找范围。
内容的提问来源于stack exchange,提问作者code_resources

