使用多个字段分隔符进行笨拙的转置数据

8
我正在尝试用一个awk命令来完成以下操作。 我有一个文本文件,其结构如下:
文件字段描述(不在文件中)
首个字段以“:”分隔,最后一个字段(主机列表)以空格分隔 唯一标识符:名称:唯一标识符:主机列表(可能为空,可能重复出现)
sv_0:blabla:205700DD4C506261796ED3:Host_10 Host_1 Host_16
sv_111:abcd:205700DD4C50629585735C:Host_10
sv_3:xpto1:2057008E714F629B3BCDCF:Host_11 Host_10
sv_46:something:205700DD4C50629E5AB93A:

需要将这个输入转换为这个输出
sv_0 blabla 205700DD4C506261796ED3 Host_10
sv_0 blabla 205700DD4C506261796ED3 Host_1
sv_0 blabla 205700DD4C506261796ED3 Host_16
sv_111 abcd 205700DD4C50629585735C Host_10
sv_3 xpto1 2057008E714F629B3BCDCF Host_11
sv_3 xpto1 2057008E714F629B3BCDCF Host_10
sv_46 something 205700DD4C50629E5AB93A

使用下一个命令是有效的,但我不喜欢一直使用管道符。 awk -F: '{print $1" "$2" "$3" "$4 }' file.txt | awk '{nfield=4; while (NF >= nfield) {print $1" "$2" "$3" "$nfield; nfield++}}'

第一个三个字段中是否可以包含空格?如果答案是“是”,请用一个例子更新问题(输入+预期输出)。 - markp-fuso
第一、二、三个字段中是否可以包含空格?如果答案是'是',请提供一个示例(输入+预期输出) - markp-fuso
第一个、第二个或第三个字段中是否可以包含空格?如果答案是“是”,请提供一个示例(输入+预期输出)来更新问题。 - undefined
不,前三个字段永远不会有空格。 - tgreis
不,前三个字段永远不会有空格。 - tgreis
4个回答

6
使用单个gawk命令:
awk -F'[: ]' '{ for (i=4;i<=NF;i++) print $1,$2,$3,$i }' file.txt

sv_0 blabla 205700DD4C506261796ED3 Host_10
sv_0 blabla 205700DD4C506261796ED3 Host_1
sv_0 blabla 205700DD4C506261796ED3 Host_16
sv_111 abcd 205700DD4C50629585735C Host_10
sv_3 xpto1 2057008E714F629B3BCDCF Host_11
sv_3 xpto1 2057008E714F629B3BCDCF Host_10
sv_46 something 205700DD4C50629E5AB93A

多个分隔符,不断学习 :) - tgreis
多个分隔符,不断学习 :) - tgreis
多个分隔符,不断学习 :) - undefined
FYI,这在任何awk中都可以运行,不仅限于gawk。 - Ed Morton
这个FYI在任何awk中都适用,不仅限于gawk。 - Ed Morton
FYI,这在任何awk中都适用,不仅限于gawk。 - undefined

4
另一种方法是将初始的字段分隔符视为一个空格,将$1的第一部分直到"Host_10"作为前缀,然后输出每个字段并将前缀附加到字段2->NF,例如。
awk '{
  gsub(/:/," ",$1)                # replace field-1 ":" to " "
  pfx=$1                          # save field-1 as prefix
  sub(/ [^ ]+$/,"",pfx)           # remove Host_x from end of prefix
  print $1                        # output full field-1
  for(i=2;i<=NF;i++)              # loop over remaining fields
    print pfx" "$i                # output prefix and field
  }
' file

示例使用/输出

使用文件dat/hostdata.txt中的数据,您将得到:

$ awk '{
>   gsub(/:/," ",$1)                # replace field-1 ":" to " "
>   pfx=$1                          # save field-1 as prefix
>   sub(/ [^ ]+$/,"",pfx)           # remove Host_x from end of prefix
>   print $1                        # output full field-1
>   for(i=2;i<=NF;i++)              # loop over remaining fields
>     print pfx" "$i                # output prefix and field
>   }
> ' dat/hostdata.txt
sv_0 blabla 205700DD4C506261796ED3 Host_10
sv_0 blabla 205700DD4C506261796ED3 Host_1
sv_0 blabla 205700DD4C506261796ED3 Host_16
sv_111 abcd 205700DD4C50629585735C Host_10
sv_3 xpto1 2057008E714F629B3BCDCF Host_11
sv_3 xpto1 2057008E714F629B3BCDCF Host_10
sv_46 something 205700DD4C50629E5AB93A

如果你有问题,请告诉我。

非常好的详细回答,谢谢分享。 - RavinderSingh13
非常好的详细答案,谢谢分享。 - RavinderSingh13
非常好的回答,非常详细,谢谢分享。 - undefined
1
谢谢您先生。使用awk有多种方法来解决问题! - David C. Rankin
1
谢谢您,先生。使用awk有不止一种方法来处理问题! - David C. Rankin
1
谢谢您先生。使用awk有多种方法来解决问题! - undefined

3
在你展示的样本中,使用GNU awk,请尝试以下awk代码。在match函数中使用正则表达式,并在那里使用正则表达式创建2个捕获组到数组arr中。
awk '
match($0,/^(.*):(.*)$/,arr){
  gsub(/ /,ORS arr[1] OFS,arr[2])
  print arr[1] (arr[2]?OFS arr[2]:"")
}
'  Input_file

2
我喜欢它。很高兴看到你使用了match()函数,并注意到GNU awk的arr扩展 :) - David C. Rankin
2
我喜欢它。很高兴看到你使用了match()并注意到GNU awk的arr扩展:) - David C. Rankin

1

最干净、最通用的方法是使用split函数进行组合。

正如在原帖中提到的,用户已经提到他有两个不同的字段分隔符,但明确指出最后一个字段有一个空格作为字段分隔符。这意味着一个分隔符优先于另一个。因此,在这种情况下,对最后一个字段执行额外的操作是有意义的。

awk 'BEGIN{FS=":"; OFS=" "}{n=split($NF,a," ")}
     { for(i=1;i<=n;++i) print $1,$2,$3,a[n] }' file

在这里,最后一个字段使用空格作为字段分隔符进行拆分。总字段数保存在变量n中,该变量用于循环遍历所有可能性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接