ksh88 AIX 根据一列中的部分字符串匹配合并两个文件

ksh88 AIX 根据一列中的部分字符串匹配合并两个文件

在 AIX 机器上使用 ksh88,我尝试了很多方法,但最终都不起作用。

File_A有 2 列没有标题:在第 1 列中创建目录的用户组,以及在第 2 列中的完整文件路径,例如:

Userwh0c4r35     /fake/file/path/directory_name
User1234567      /another/file/path/different_dir
User0987654      /some/other/path/another_name

File_B有 2 列,没有标题:第 1 列中的目录大小(以 MB 为单位),第 2 列中的目录的部分路径名,例如:

2183.31     directory_name
1750.09     directory_name/subfolder
1028.14     directory_name/subfolder/sub_subfolder
3658.97     different_dir
2159.62     different_dir/subfolder
1001.01     different_dir/different_subfolder 

ETC。

问题是File_B(ie, directory_name, directory_name/subfolder, directory_name/subfolder/sub_subfolder, ...)中有重复的目录名称

我想要的是,在一个文件中,这个输出(老实说,我不关心列的顺序,只是它们都存在):

Userwh0c4r35     /fake/file/path/directory_name     2183.31
User1234567      /another/file/path/different_dir   3658.97

这看起来很简单,但我一直无法弄清楚。我能得到的最接近的是从找到部分匹配的两个文件中获取用户组、完整路径名和行号,但我无法获取目录大小(来自 的第 1 列File_B)...

我已经确定的代码让我如此接近但还没有完全实现(从SO和各种在线教程中拼凑而成)是:

awk '
NR==FNR {
    a[$2]=$1
    next
}
{
    for(i in a) 
        if($2 ~ i) 
            {print $2,a[$2],$1} 
}' file_B file_A 

它会生成一个列表,其中每一行都有重复项,File_A其中第 2 列 fromFile_A与第 2 列 from 部分匹配File_B,例如:

Userwh0c4r35     /fake/file/path/directory_name
Userwh0c4r35     /fake/file/path/directory_name
Userwh0c4r35     /fake/file/path/directory_name

directory_name( 、 、directory_name/subfolder和各一个directory_name/subfolder/sub_subfolder

我已经尝试了print我能想到的一切,但无济于事......NR,FNR,i,$0,a[$NR],a[$FNR],a[$1],a[$2],$1,$2我也尝试过使用,printf但也没有用......

答案1

您想要的本质上是两个数据库表的联接。方便的是,有一个命令可以实现这一点,恰当地命名为join.

这里不需要awk。请注意,我既没有 AIX ksh88,也没有 AIX;这是 Linux 上的 Bash,但我很快检查了AIX手册并认为它应该有效。

我准备了这个测试环境:

$ cat filea
Userwh0c4r35     /fake/file/path/directory_name5
Userwh0c4r36     /fake/file/path/directory_name6
Userwh0c4r37     /fake/file/path/directory_name7
$ cat fileb
1234    directory_name5
2345    directory_name6
3456    directory_name7

步骤1:添加一列filea仅包含目录路径名的最后一部分:

$ sed 's|\(.*\)/\(.*\)|\1/\2 \2|' filea > filea.tmp
$ cat filea.tmp
Userwh0c4r35     /fake/file/path/directory_name5 directory_name5
Userwh0c4r36     /fake/file/path/directory_name6  directory_name6
Userwh0c4r37     /fake/file/path/directory_name7  directory_name7

第2步:按目录名称对两个文件进行排序(感谢 Mark Plotnick 指出这一点):

$ sort -k3 filea.tmp > filea.tojoin
$ sort -k2 fileb > fileb.tojoin

步骤3:根据第 3 列 ( ) 和第 2 列 ( )中的目录名称,使用join与 进行连接:filebfileafileb

$ join -1 3 -2 2 filea.tojoin fileb.tojoin > result
$ cat result
directory_name5 Userwh0c4r35 /fake/file/path/directory_name5 1234
directory_name6 Userwh0c4r36 /fake/file/path/directory_name6  2345
directory_name7 Userwh0c4r37 /fake/file/path/directory_name7  3456

可选步骤 4cut如果您不想要的话,A 将删除第一列。

答案2

目前尚不清楚您要做什么,并且您的示例输入/输出当前对于测试没有用,但这是一个猜测:

$ cat tst.awk
BEGIN { OFS="\t" }
{
    val = $1                                    # val = Userwh0c4r35 or 2183.31
    sub(/^[^[:space:]]+[[:space:]]+/,"")        # Allows spaces in directory names vs using $2
    dir = $0                                    # dir = /fake/file/path/directory_name or directory_name/subfolder
}
NR==FNR {
    sub(".*/","",dir)                           # dir = directory_name
    dir2path[dir] = $0
    dir2grp[dir]  = val
    next
}
{
    sub("/.*","",dir)                           # dir = directory_name
    print dir2grp[dir], dir2path[dir], val
}

$ awk -f tst.awk File_A File_B
Userwh0c4r35    /fake/file/path/directory_name  2183.31
Userwh0c4r35    /fake/file/path/directory_name  12345
Userwh0c4r35    /fake/file/path/directory_name  9876

上面假设相同的内容directory_name不能出现在 File_A 中不同路径的末尾(例如/foo/directory_name/bar/directory_name),并且在这些输入文件上运行:

$ head File_*
==> File_A <==
Userwh0c4r35     /fake/file/path/directory_name

==> File_B <==
2183.31     directory_name
12345       directory_name/subfolder
9876        directory_name/subfolder/sub_subfolder

如果您的目录名称可以包含制表符,那么您需要使用不同的输出格式。如果它们可以包含换行符,那么您也需要不同的输入格式。

相关内容