shell awk或sed命令用于从多个文件中选择列和行

o2rvlv0m  于 2023-02-09  发布在  Shell
关注(0)|答案(4)|浏览(265)

正在查找用于以下任务的命令:
我有三个文件,每个文件有两列,如下所示。我想创建四列的file4
输出应类似于file1file2file3的合并排序版本,其中第一列已排序,第二列是file1的第二列,第三列是file2的第二列,第四列是file3的第二列。
列2到3中的条目不应排序,但应与原始文件第一列中的 key 值匹配。
我在Linux中尝试了交集,但没有给出所需的输出。
任何帮助将不胜感激。提前感谢!!

$ cat -- file1                
A1     B5
A10    B2
A3     B15
A15    B6
A2     B10
A6     B19
$ cat -- file2
A10 C4
A4  C8
A6  C5
A3  C10
A12 C14
A15 C18
$ cat -- file 3
A3  D1
A22 D9
A20 D3
A10 D5
A6  D10
A21 D11

$ cat -- file 4
col1 col2    col3    col4
A1   B5
A2   B10
A3   B15      C10     D1
A4            C8 
A6   B19      C5      D10
A10  B2       C4      D5
A12           C14
A15  B6       C18
A20                   D3
A21                   D11
A22                   D9
okxuctiv

okxuctiv1#

Awk + Bash版本:
( echo "col1, col2, col3, col4" &&
awk 'ARGIND==1 { a[$1]=$2; allkeys[$1]=1 } ARGIND==2 { b[$1]=$2; allkeys[$1]=1 } ARGIND==3 { c[$1]=$2; allkeys[$1]=1 }
    END{
        for (k in allkeys) {
            print k", "a[k]", "b[k]", "c[k]
        }
    }' file1 file2 file3 | sort -V -k1,1 ) | column -t -s ','
纯Bash版本:
declare -A a
while read key value; do a[$key]="${a[$key]:-}${a[$key]:+, }$value"; done < file1
while read key value; do a[$key]="${a[$key]:-, }${a[$key]:+, }$value"; done < file2
while read key value; do a[$key]="${a[$key]:-, , }${a[$key]:+, }$value"; done < file3

(echo "col1, col2, col3, col4" &&
for i in ${!a[@]}; do 
    echo $i, ${a[$i]}
done | sort -V -k1,1) | column -t -s ','

"${a[$key]:-, , }${a[$key]:+, }$value"的解释,请检查 shell -参数-扩展

o3imoua4

o3imoua42#

使用GNU Awk:

gawk '{ a[$1] = substr($1, 1); b[$1, ARGIND] = $2 }
    END {
        PROCINFO["sorted_in"] = "@val_num_asc"
        for (i in a) {
            t = i
            for (j = 1; j <= ARGIND; ++j)
                t = t OFS b[i, j]
            print t
        }
    }' file{1..3} | column -t
lx0bsm1f

lx0bsm1f3#

有一个名为join的简单工具可用于执行此操作:

#!/usr/bin/env bash
cut -d ' ' -f1 file{1,2,3} | sort -k1,1 -u > ftmp
for f in file1 file2 file3; do
   mv -- ftmp file4
   join -a1 -e "---" -o auto file4 <(sort -k1,1 "$f") > ftmp
done
sort -k1,1V ftmp > file4
cat file4

此输出

A1 B5 --- ---
A2 B10 --- ---
A3 B15 C10 D1
A4 --- C8 ---
A6 B19 C5 D10
A10 B2 C4 D5
A12 --- C14 ---
A15 B6 C18 ---
A20 --- --- D3
A21 --- --- D11
A22 --- --- D9

我使用---来表示一个空字段,如果你想漂亮地打印它,你必须用awk或其他东西重新解析它。

j5fpnvbx

j5fpnvbx4#

这可能对你有用(GNU sed和sort):

s=''; for f in file{1,2,3}; do s="$s\t"; sed -E "s/\s+/$s/" $f; done |
sort -V | 
sed -Ee '1i\col1\tcol2\tcol3\tcol4' -e ':a;N;s/^((\S+\t).*\S).*\n\2\t+/\1\t/;ta;P;D'

用制表符替换空格,并根据正在处理的文件在键和值之间插入制表符的数量。
按键列顺序对输出进行排序。
将每行与其键合并并打印结果。

相关问题