如何在Bash脚本的awk命令中正确传入变量实现字段匹配?
问题描述
你编写了一段Bash脚本,试图循环读取col.txt文件的每行内容存入col变量,再将该变量传入awk命令,用来匹配75437_kbart.txt的第22个字段,但脚本执行后没有任何输出结果。不过在命令行硬编码具体值(比如col.txt中的EBSCOhost.a9h)时,能正常得到匹配结果。你尝试了多种变量传递方式均无效,还误以为awk的-v选项仅在BEGIN/END块中生效,现在需要知道如何修改awk参数,才能正确传入文件行变量实现匹配效果。
原始脚本
#!/bin/bash while read col; do awk -F'\t' '$22~/$col/' 75437_kbart.txt >> titles.txt done <col.txt
尝试过的无效写法
# 写法1 awk -F'\t' '$22~/$col/' 75437_kbart.txt >> titles.txt # 写法2 awk -F'\t' '$22~/var/' var="$col" 75437_kbart.txt >> titles.txt # 写法3 awk -v var="$col" -F'\t' '$22~/var/' 75437_kbart.txt >> titles.txt # 写法4 awk -F'\t' '$22~/var/' 75437_kbart.txt var="${col}" >> titles.txt
正确解决方法
方法1:正确使用-v传递变量
你之前误解了-v选项的作用——它不仅能在BEGIN/END块中使用,在awk的主处理代码里也完全有效。之前的错误在于用/var/时,awk会把var当成字面字符串匹配,而不是引用变量。正确的做法是直接用变量名,不需要斜杠包裹:
#!/bin/bash while read col; do awk -F'\t' -v col_val="$col" '$22 ~ col_val' 75437_kbart.txt >> titles.txt done <col.txt
如果需要精确匹配(而不是字段包含变量值),可以把~换成==:
awk -F'\t' -v col_val="$col" '$22 == col_val' 75437_kbart.txt >> titles.txt
方法2:通过环境变量传递
也可以把bash变量作为环境变量传给awk,在awk内部用ENVIRON["变量名"]来引用:
#!/bin/bash while read col; do COL_VAL="$col" awk -F'\t' '$22 ~ ENVIRON["COL_VAL"]' 75437_kbart.txt >> titles.txt done <col.txt
方法3:高效写法(避免循环调用awk)
每次循环都启动一次awk进程效率很低,尤其是当col.txt行数较多时。可以一次性把col.txt的内容读进awk数组,再扫描75437_kbart.txt完成匹配,只需要调用一次awk:
awk -F'\t' ' # 处理第一个文件col.txt,把每行存入数组cols的键 NR == FNR { cols[$0]; next } # 处理第二个文件,第22个字段在cols数组中就输出该行 $22 in cols ' col.txt 75437_kbart.txt >> titles.txt
内容的提问来源于stack exchange,提问作者trogne
相关产品推荐
相关产品推荐

