Unix中基于lookup文件识别分隔文件行:脚本修复及效率优化
问题修复与效率分析
脚本错误修复
你写的脚本出错的核心原因是:awk无法直接识别shell变量$line和$outputFile,且输出重定向的语法逻辑错误。
错误版本的问题点
- awk内部的
$line会被当作awk的字段引用(比如$1、$2),而非shell传递过来的lookup行内容 >> $outputFile里的$outputFile没有被shell解析,awk无法识别这个变量,导致重定向失败
修复后的基础版本(先解决错误,暂不优化效率)
如果要先让脚本正常执行,可以用awk的-v选项把shell变量传递进去:
#!/bin/sh lookupFile=$1 #lookup.txt inputFile=$2 #input.txt outputFile=$3 #output.txt # 先清空输出文件,避免重复追加内容 > "$outputFile" while IFS= read -r line do awk -F'~' -v target="$line" -v out="$outputFile" '$3 == target { print >> out }' "$inputFile" done < "$lookupFile"
这个版本能正常跑通,但效率极低,下文会详细说明。
大文件场景下的效率问题
你的原始方法(包括上面的修复版)效率非常差:
- 每读取lookup.txt里的一行,就要完整遍历一次input.txt
- 假设lookup有1000行、input有1000行,就要执行1000×1000=100万次行匹配,时间复杂度为O(M*N),文件越大运行速度越慢
高效解决方案(仅遍历两次文件,O(M+N)复杂度)
正确的做法是把lookup.txt的所有内容加载到awk的哈希数组中,然后只遍历一次input.txt进行匹配,无论文件规模多大,效率都能得到保证:
#!/bin/sh lookupFile=$1 #lookup.txt inputFile=$2 #input.txt outputFile=$3 #output.txt awk -F'~' ' # 处理第一个文件(lookup.txt),将货币代码存入数组 NR == FNR { codes[$0] = 1; next } # 处理第二个文件(input.txt),判断第三列是否在数组中 $3 in codes { print } ' "$lookupFile" "$inputFile" > "$outputFile"
代码解释
NR == FNR:当处理第一个文件(lookup.txt)时该条件成立,把每一行的货币代码作为键存入codes数组next:跳过后续逻辑,继续处理lookup的下一行- 处理第二个文件(input.txt)时,直接判断第三列
$3是否存在于codes数组中,存在则打印该行 - 最后用
> "$outputFile"统一输出,避免awk内部多次打开关闭文件,进一步提升效率
内容的提问来源于stack exchange,提问作者DBreaker
相关产品推荐
相关产品推荐

