我有一个文件,其字段为ID、Designation、ParentID和ParentDesignation。文件内容如下。
A1 M.D-Sales 0 UmbrellaCorp
a1 Sr.Sales A1
b1 Sr.R&D B1
b2 Jr.SR&D B1
a2 Jr.Sales A1
B1 M.D-R&D 0 UmbrellaCorp
Run Code Online (Sandbox Code Playgroud)
我想为那些缺少第四列的行获取ParentDesignation,这基本上意味着:
结果将是以下一个。
A1 M.D-Sales 0 UmbrellaCorp
a1 Sr.Sales A1 M.D-Sales
b1 Sr.R&D B1 M.D-R&D
b2 Jr.SR&D B1 M.D-R&D
a2 Jr.Sales A1 M.D-Sales
B1 M.D-R&D 0 UmbrellaCorp
Run Code Online (Sandbox Code Playgroud)
我知道如何在 Excel 中使用 完成相同的任务vlookup,但我需要使用脚本。
最终答案在下面给出了更多评论并更新了有问题的示例输入/输出:
我会首先对数据进行排序,因此填充缺失值的行为比在 awk 中执行 2-pass 方法更有效并且使用更少的内存,并且最终输出的组织比输入的可读性要好得多:
$ cat tst.sh
#!/usr/bin/env bash
awk '
BEGIN { FS=OFS="\t" }
{ print (NR>1), ($4=="" ? $3 : $1), $4, $1, NR, $0 }
' "${@:--}" |
sort -t$'\t' -k1,1n -k2,2 -k3,3r -k4,4 -k5,5n |
cut -f6- |
awk '
BEGIN { FS=OFS="\t" }
$4 != "" { d = $2 }
$4 == "" { $4 = d }
{ print }
'
Run Code Online (Sandbox Code Playgroud)
$ ./tst.sh file | column -s$'\t' -t
ID Designation ParentID ParentDesignation
A1 M.D-Sales 0 UmbrellaCorp
a1 Sr.Sales A1 M.D-Sales
a2 Jr.Sales A1 M.D-Sales
B1 M.D-R&D 0 UmbrellaCorp
b1 Sr.R&D B1 M.D-R&D
b2 Jr.SR&D B1 M.D-R&D
Run Code Online (Sandbox Code Playgroud)
对 awk 的第一次调用只是修饰输入,以便它可以按以下方式排序:
(NR>1) = header-or-not 0-or-1 指示符,以确保排序后标题行保持在最前面,($4=="" ? $3 : $1) = 每行的 ID 或 ParentID 将相关行组合在一起$4 = ParentDesignation,所以我们可以对它进行排序,使得具有 ParentDesignation 的行排在那些不具有相同 ID/ParentID 的行之前,$1 = ID,这样我们就可以按孩子的 ID 按字母顺序对孩子进行排序,NR = 所以如果其他所有东西都是通用的,我们可以按照它们在输入中出现的顺序打印这些行(在这种情况下可能没有必要,因为每个 ID 似乎都是唯一的,但对于其他类似情况是一种很好的做法)。然后我们只是sort通过上面的字段,然后cut在传递给最终awk脚本以实际进行$4填充之前使用删除装饰。
如果您不确定其中任何一个步骤的作用,只需一次将每个步骤更改|为| cat; exit一个,然后您就会看到每个步骤发生了什么。
上一个答案:
鉴于下面的评论,这可能是您想要的,假设父项(如果存在)始终出现在您的数据中的子项之前:
$ cat tst.awk
BEGIN { FS=OFS="\t" }
$4 != "" {
id2des[$1] = $2
}
$4 == "" {
$4 = id2des[$3]
}
{ print }
Run Code Online (Sandbox Code Playgroud)
$ awk -f tst.awk file
ID Designation ParentID ParentDesignation
A1 M.D-Sales 0 UmbrellaCorp
a1 Sr.Sales A1 M.D-Sales
a2 Jr.Sales A1 M.D-Sales
B1 M.D-R&D 0 UmbrellaCorp
b1 Sr.R&D B1 M.D-R&D
b2 Jr.SR&D B1 M.D-R&D
Run Code Online (Sandbox Code Playgroud)
原答案:
您的问题实际上似乎比您指定的更简单,因为您似乎有一个包含所有信息的父行,后跟缺少 $4 的子行,在这种情况下,您不需要查找任何内容,您只需要:
$ awk 'BEGIN{FS=OFS="\t"} $4!=""{d=$2} $4==""{$4=d} 1' file
ID Designation ParentID ParentDesignation
A1 M.D-Sales 0 UmbrellaCorp
a1 Sr.Sales A1 M.D-Sales
a2 Jr.Sales A1 M.D-Sales
B1 M.D-R&D 0 UmbrellaCorp
b1 Sr.R&D B1 M.D-R&D
b2 Jr.SR&D B1 M.D-R&D
Run Code Online (Sandbox Code Playgroud)
$ awk 'BEGIN{FS=OFS="\t"} $4!=""{d=$2} $4==""{$4=d} 1' file | column -s$'\t' -t
ID Designation ParentID ParentDesignation
A1 M.D-Sales 0 UmbrellaCorp
a1 Sr.Sales A1 M.D-Sales
a2 Jr.Sales A1 M.D-Sales
B1 M.D-R&D 0 UmbrellaCorp
b1 Sr.R&D B1 M.D-R&D
b2 Jr.SR&D B1 M.D-R&D
Run Code Online (Sandbox Code Playgroud)