鉴于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
(或使用$anything
)END
,因为该部分中的$0
、等值是每个 POSIX 未定义的行为。在某些 awks 中,该部分将是最后一行读取的第一个字段的值,在其他 awks 中它将为 null,而在其他 awks 中它可能是其他任何值。$1
END
$1
END
在每个 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
我建议您使用head
和tail
来处理大型输入文件,因为awk
和sed
处理大型文件速度很慢。
$ 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