我有一个文件,其字段是ID,指定,家长ID, 和家长指定。文件内容如下。
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
我想要得到家长指定对于那些缺少第四列的行,这本质上意味着:
- 读取每一行
- 得到家长ID从第三列开始
- 将其与第一列中的值匹配
- 将其插入到该子项前面的第四列 4 中。
结果将如下所示。
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
我知道如何在 Excel 中使用 执行相同的任务vlookup
,但我需要使用脚本。
答案1
最终答案在下面给出了更多评论并更新了相关示例输入/输出:
我首先对数据进行排序,这样填充缺失值的行为比在 awk 中执行 2 遍方法更有效,并且使用更少的内存,并且最终输出比输入的可读性更好地组织:
$ 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 }
'
$ ./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
对 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 }
$ 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
原答案:
您的问题实际上似乎比您指定的更简单,因为您似乎有一个包含所有信息的父行,后跟缺少 $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
$ 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
答案2
如果父母总是出现在孩子面前......
awk -F"\t" -v OFS="\t" '
{dad[$1]=$2}
!$4{$4=dad[$3]}1
' file
如果没有,则运行两次......
awk -F"\t" -v OFS="\t" '
NR==FNR{dad[$1]=$2;next}
!$4{$4=dad[$3]}1
' file file
答案3
另一个非常相似的解决方案:一个 (gnu)awk 多行脚本,访问输入文件两次,尝试使用垂直对称。 $ cat awklookup
#!/usr/bin/awk -f
BEGIN{FS=OFS="\t";
ARGC=3; ARGV[2] = ARGV[1]} ## visit the input file twice
ARGIND==1 { tab[$1]=$2 }
ARGIND==2 && !$4 { $4=tab[$3] }
ARGIND==2 { print }
然后:
$ chmod 755 awklookup
$ ./awklookup infile
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