AWK:连接来自不同记录的字段

AWK:连接来自不同记录的字段

鉴于file

2018-03-22 foo/bar/baz
2020-09-30 Lorem/ipsum/dolor
2021-10-01 yadda/yadda/yadda
2022-03-14 blah/blah/blah

(实际文件包含数千个这样的行)

如何获取字符串2018-03-22_2022-03-14?这是记录 1 中字段 1 的串联,后跟下划线,然后是最后一条记录中的字段 1。

我想出了这个:

$ awk 'BEGIN{ORS="_"}NR==1{print $1} END{print $1}' file | sed 's/_$//'
2018-03-22_2022-03-14

它有效,但似乎应该有一个不复杂的awk仅使用或可能仅sed使用而不使用管道或子外壳来获得相同结果的方法。事实上有这样的方法吗?

答案1

唯一的版本sed

sed 's/ .*//;1h;$!d;H;g;y/\n/_/' file
  • 用于s/ .*//删除空格后的所有内容,仅保留日期
  • 1h复制空格1中的行日期hold
  • $!d d删除除最后一行之外的所有行
  • 如果我们到达这里,我们就在最后一行,所以我们将这一行H与我们的第一个日期附加到旧空间,然后将两者复制到模式空间中g
  • 现在剩下要做的唯一一件事就是用下划线替换嵌入的换行符(由于附加):y/\n/_/

(是的,它有点短)

答案2

为了可移植性,不要在该部分中执行print $1(或使用$anythingEND,因为该部分中的$0、等值是每个 POSIX 未定义的行为。在某些 awks 中,该部分将是最后一行读取的第一个字段的值,在其他 awks 中它将为 null,而在其他 awks 中它可能是其他任何值。$1END$1END

在每个 Unix 机器上的任何 shell 中使用任何 awk:

$ awk -v OFS='_' 'NR==1{beg=$1} {end=$1} END{print beg, end}' file
2018-03-22_2022-03-14

_或者在输入文件为空时避免打印单个文件:

awk -v OFS='_' 'NR==1{beg=$1} {end=$1} END{ if (NR) print beg, end}' file

上面假设如果输入中只有 1 行,您希望$1在它们之间重复相同的值_。如果这不是您想要的,请更新您的问题以澄清您对该案例的要求。

答案3

用于printf控制输出:

$ awk 'NR==1{printf("%s_", $1)}END{print $1}' f
2018-03-22_2022-03-14

答案4

我建议您使用headtail来处理大型输入文件,因为awksed处理大型文件速度很慢。

$ cat input.txt
2018-03-22 foo/bar/baz
2020-09-30 Lorem/ipsum/dolor
2021-10-01 yadda/yadda/yadda
2022-03-14 blah/blah/blah
{ head -n1 input.txt && tail -n1 input.txt; } |
  cut -d ' ' -f1 | paste -sd _ -
2018-03-22_2022-03-14

相关内容