如何用awk从含50万列的空格分隔文件提取指定4.5万列
用Awk解决大文件列提取(规避cut参数过长问题)
我有一个a.txt文件,包含500,000列、2000行,首行为表头;另一个b.txt每行对应需要提取的45000个列名。想要从a.txt中提取对应列,生成空格分隔的c.txt。尝试用cut命令时出现「argument list too long」错误,求可行的Awk解决方案。
文件示例
a.txt(仅展示前9列)
chromosome SNPID rsid position alleleA alleleB 2409086 3514581 3635346 1 1:55487346_C_G rs12117661 55487346 C G 1 0 0 1 1:55487648_A_G rs11588151 55487648 A G 1 0 0 1 1:55489542_C_T rs34232196 55489542 C T 1 0 0 1 1:55490861_T_C rs4500361 55490861 T C 1 0 0 1 1:55491702_T_C rs4927191 55491702 T C 0.894118 0 0 1 1:55491780_A_G rs200159426 55491780 A G 0.894118 0 0
b.txt
chromosome SNPID rsid position alleleA alleleB 2409086 3635346
预期输出c.txt
chromosome SNPID rsid position alleleA alleleB 2409086 3635346 1 1:55487346_C_G rs12117661 55487346 C G 1 0 1 1:55487648_A_G rs11588151 55487648 A G 1 0 1 1:55489542_C_T rs34232196 55489542 C T 1 0 1 1:55490861_T_C rs4500361 55490861 T C 1 0 1 1:55491702_T_C rs4927191 55491702 T C 0.894118 0 1 1:55491780_A_G rs200159426 55491780 A G 0.894118 0
尝试失败的cut命令
cut -f 1,$( head -n1 a.txt | tr ' ' '\n' | grep -nf b.txt | sed ':a;$!N;s/:[^\n]*\n/,/;ta;s/:.*//' ) a.txt > c.txt
报错信息:
-bash: /usr/bin/cut: Argument list too long
Awk解决方案
直接用Awk一次性处理两个文件,彻底规避参数过长问题:
awk ' BEGIN { FS = OFS = " " } NR == FNR { cols[$1] = 1; next } FNR == 1 { for (i = 1; i <= NF; i++) { if ($i in cols) { keep[i] = 1 order[++k] = i } } } { for (i = 1; i <= k; i++) { printf "%s%s", $(order[i]), (i < k ? OFS : ORS) } } ' b.txt a.txt > c.txt
方案说明
- 开头设置输入输出分隔符为空格,适配你的文件格式
- 先读取b.txt,把需要提取的列名存入
cols数组做标记 - 读取a.txt表头时,逐个检查列名是否在标记列表中,记录需要保留的列位置,同时按顺序存储(保证输出列顺序和b.txt一致)
- 处理a.txt每一行数据时,按记录好的列位置依次输出内容,列间用空格分隔,行尾自动换行
这个方案不需要生成超长参数列表,直接在Awk内部完成匹配提取,既解决了cut的参数限制问题,处理大文件的效率也很高。
内容的提问来源于stack exchange,提问作者Lena
相关产品推荐
相关产品推荐

