将一个文件中的一列作为最后一列添加到另一个文件中

将一个文件中的一列作为最后一列添加到另一个文件中

我想创建一个循环,其中文本文件中的特定列(在我的例子中为第 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 循环中的解决方案:

  1. 将第一个文件的第 4 列(以文件名作为标题)写入NEW.
awk -F'\t' 'NR==1{print FILENAME; next} {print $4}' V1 > NEW
  1. 将其他文件的第 4 列(以文件名作为标题)附加到NEWfor 循环中。使用临时文件 ( 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

相关内容