如何在循环中传递变量至AWK脚本以实现条件行提取?
循环传递变量到AWK脚本的问题修复
需求与输入示例
需要循环执行AWK脚本,根据指定列表中的变量,提取第一列和第三列部分匹配该变量的行。输入文件格式如下:
pop1_io 1 pop1_ei 2 1 62027313 63797977 3.047 pop1_eg 1 pop2_yu 2 1 74240214 78974955 3.827 pop3_ab 1 pop1_zx 2 1 160604473 163511425 4.04
手动指定变量的AWK脚本可正常运行:
awk '{if ($1 ~ /pop1/ && $3 ~ /pop1/) print $1"\t" $2 "\t" $3 "\t" $4"\t" $5 "\t" $6 "\t" $7 "\t" $8}' inputfile.ibd | sed -r '/^\s*$/d' > pop1.ibd
但以下两个循环传递变量的脚本均失效:
脚本1:无输出
pops="pop1 pop2 pop3" for pop in $pops do awk '{if ($1 ~ /$pop/ && $3 ~ /$pop/) print $1"\t" $2 "\t" $3 "\t" $4"\t" $5 "\t" $6 "\t" $7 "\t" $8}' inputfile.ibd | sed -r '/^\s*$/d' > out.$pop.ibd done
脚本2:输出全部内容
for pop in $pops do awk '{if (a[$1]=~$pop && a[$3]=~$pop) print $1"\t" $2 "\t" $3 "\t" $4"\t" $5 "\t" $6 "\t" $7 "\t" $8}' Roma_Czech.ibdne.ibd | sed -r '/^\s*$/d' > out.$pop.ibd done
问题分析与修复方案
脚本1失效原因与修复
- 问题:AWK的单引号会屏蔽Shell变量解析,
/$pop/里的$pop不会被替换成循环中的变量值,而是被当作字面量匹配,自然找不到对应行。 - 修复方案:使用AWK的
-v选项将Shell变量传递到AWK环境中,直接在匹配条件中使用该变量。
修复后的脚本1:
pops="pop1 pop2 pop3" for pop in $pops do awk -v target="$pop" '{if ($1 ~ target && $3 ~ target) print $1"\t" $2 "\t" $3 "\t" $4"\t" $5 "\t" $6 "\t" $7 "\t" $8}' inputfile.ibd | sed -r '/^\s*$/d' > out.$pop.ibd done
脚本2失效原因与修复
- 问题:
a[$1]是未赋值的关联数组,默认值为空字符串。空字符串与任何变量用~匹配都会返回真,导致所有行都被输出。 - 修复方案:去掉多余的数组
a,直接用$1和$3进行匹配,同时采用脚本1的变量传递方式。
修复后的脚本2:
pops="pop1 pop2 pop3" for pop in $pops do awk -v target="$pop" '{if ($1 ~ target && $3 ~ target) print $1"\t" $2 "\t" $3 "\t" $4"\t" $5 "\t" $6 "\t" $7 "\t" $8}' Roma_Czech.ibdne.ibd | sed -r '/^\s*$/d' > out.$pop.ibd done
额外优化
可以将Sed的去空行逻辑整合到AWK中,减少管道调用:
pops="pop1 pop2 pop3" for pop in $pops do awk -v target="$pop" 'NF && $1 ~ target && $3 ~ target { print $1"\t" $2 "\t" $3 "\t" $4"\t" $5 "\t" $6 "\t" $7 "\t" $8 }' inputfile.ibd > out.$pop.ibd done
这里NF表示行中字段数大于0,即非空行,替代了Sed的作用。
内容的提问来源于stack exchange,提问作者Gf.Ena
相关产品推荐
相关产品推荐

