Bash聚合同前缀文件去重表头遇执行时序问题求解决
问题根源分析
你的wait命令完全无效,因为find是前台执行的命令,会阻塞到执行完成才会继续后续代码,wait仅能等待后台进程。报错的真正原因大概率是第二个find命令未找到匹配文件,导致fl变量为空,执行head -n1 $fl时出错,进而cat命令失败,没有生成tmp.txt,所以mv报错。
解决方案
修改函数逻辑,先获取表头再处理内容,同时增加错误判断,避免空文件或无效操作:
aggr () { local prefix="$1" local outfile="${prefix}_aggregate.txt" local tmpfile="tmp_${prefix}.txt" # 先找到第一个匹配的文件,获取表头 local first_file first_file=$(find . -name "${prefix}_*.txt" -print -quit) if [ -z "$first_file" ]; then echo "错误:未找到前缀为${prefix}_的txt文件" return 1 fi local header header=$(head -n1 "$first_file") if [ -z "$header" ]; then echo "错误:文件${first_file}没有表头" return 1 fi # 写入表头到临时文件 echo "$header" > "$tmpfile" # 追加所有匹配文件的内容(跳过表头) find . -name "${prefix}_*.txt" -exec tail -n+2 {} \; >> "$tmpfile" # 替换最终输出文件 mv "$tmpfile" "$outfile" }
改进点说明
- 调整执行顺序:先获取表头再处理内容,确保表头一定能拿到,避免后续依赖空变量的错误。
- 增加错误判断:检查是否找到匹配文件、表头是否有效,提前终止并给出提示,避免无意义的操作。
- 临时文件命名唯一:用前缀作为临时文件名的一部分,避免多个
aggr命令同时执行时冲突。 - 简化流程:直接将表头写入临时文件,再追加内容,不需要用
cat - $outfile <<< "$header"这种易出错的写法。
如果你确定所有匹配文件都在当前目录(不需要递归查找),可以用glob替代find,效率更高:
aggr () { local prefix="$1" local outfile="${prefix}_aggregate.txt" local tmpfile="tmp_${prefix}.txt" local files=("${prefix}_"*.txt) if [ ${#files[@]} -eq 0 ] || [ ! -f "${files[0]}" ]; then echo "错误:未找到前缀为${prefix}_的txt文件" return 1 fi local header header=$(head -n1 "${files[0]}") if [ -z "$header" ]; then echo "错误:文件${files[0]}没有表头" return 1 fi echo "$header" > "$tmpfile" for file in "${files[@]}"; do tail -n+2 "$file" >> "$tmpfile" done mv "$tmpfile" "$outfile" }
内容的提问来源于stack exchange,提问作者danny
相关产品推荐
相关产品推荐

