在 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
与 进行连接:fileb
filea
fileb
$ 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
可选步骤 4:cut
如果您不想要的话,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
如果您的目录名称可以包含制表符,那么您需要使用不同的输出格式。如果它们可以包含换行符,那么您也需要不同的输入格式。