我想创建一个循环,其中文本文件中的特定列(在我的例子中为第 4 列)被添加为新文本文件的最后一列。我总共有大约 500 个文本文件 (V1-V500),我想从中获取第四列并将其添加到新的文本文件中(各列由制表符分隔)。所有文本文件都具有相同的行数。此外,添加的列的标题应包含其最初来源的文本文件的文件名。我已经尝试使用 awk 和 for 循环制定命令行,但我的命令都不起作用。我已经尝试过基于以前的命令行的命令行邮政。我正在使用可用的 GNU 工具在 Linux 中工作。
举个例子:V1文本文件
header1 header2 header3 header4
1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16
V2文本文件:
header1 header2 header3 header4
17 25 21 29
18 26 22 30
19 27 23 31
20 28 24 32
新文本文件:
V1 V2
13 29
14 30
15 31
16 32
感谢您的帮助!
答案1
解析awk
所有文件。
awk -F'\t' -v OFS='\t' '{
x = (FNR==1 ? FILENAME : $4)
a[FNR] = (FNR==NR ? x : a[FNR] OFS x)
}
END {
for (i=1;i<=FNR;i++) print a[i]
}' V{1..500}
x
是我们从每条生产线上保留下来的东西,也是a
我们建造的新生产线。两者都使用分配条件表达式。FNR
是当前输入文件的行号,NR
总行数。FNR==NR
意思是“解析第一个文件时”。我还假设了制表符分隔的输入和输出。
答案2
非 awk 解决方案:
#!/bin/bash
for num in {1..500}; do
echo V$num > temp_$num #put the filename as header
< V$num tail -n+2 | cut -f4 >> temp_$num #get the contents of column 4
if [[ -f V_new ]]; then #if not first iteration
paste V_new temp_$num > temp #combine previous files with current file
mv temp V_new
else # if first iteration
mv temp_$num V_new
fi
done
答案3
虽然您可以使用 awk 或其他此类工具来完成此操作,但我建议在这里使用更简单的方法:
$ printf 'paste ' > script
$ printf "<(awk 'NR==1{print FILENAME; next}{print \$4}' %s) \\\\\n" V{1..500} >> script
$ sh ./script
这将paste
在文件中创建一个复杂的命令,script
如下所示:
$ head script
paste <(awk 'NR==1{print FILENAME; next}{print $4}' V1) \
<(awk 'NR==1{print FILENAME; next}{print $4}' V2) \
<(awk 'NR==1{print FILENAME; next}{print $4}' V3) \
<(awk 'NR==1{print FILENAME; next}{print $4}' V4) \
<(awk 'NR==1{print FILENAME; next}{print $4}' V5) \
<(awk 'NR==1{print FILENAME; next}{print $4}' V6) \
<(awk 'NR==1{print FILENAME; next}{print $4}' V7) \
<(awk 'NR==1{print FILENAME; next}{print $4}' V8) \
<(awk 'NR==1{print FILENAME; next}{print $4}' V9) \
<(awk 'NR==1{print FILENAME; next}{print $4}' V10) \
因此,执行将使用 awk 命令script
运行,提取 500 个输入文件中每个文件的第 4 列。paste
使用示例中的两个文件,将产生:
$ printf 'paste ' > script
$ printf "<(awk 'NR==1{print FILENAME; next}{print \$4}' %s) \\\\\n" V* >> script
$ sh ./script
V1 V2
13 29
14 30
15 31
16 32
答案4
使用 awk 并粘贴到 for 循环中的解决方案:
- 将第一个文件的第 4 列(以文件名作为标题)写入
NEW
.
awk -F'\t' 'NR==1{print FILENAME; next} {print $4}' V1 > NEW
- 将其他文件的第 4 列(以文件名作为标题)附加到
NEW
for 循环中。使用临时文件 (temp
) 收集输出,然后将其内容移至NEW
每次迭代中。
for file in V{2..500}; do
paste NEW <(awk -F'\t' 'NR==1{print FILENAME; next} {print $4}' $file) > temp && mv -f temp NEW
done