SED 是否能够将此前缀 =a,b,c,d 拆分为该前缀 =a 前缀=b 前缀=c

  • 本文关键字:前缀 拆分 是否 SED awk sed
  • 更新时间 :
  • 英文 :


有一个日志文件,其中包含以下数据: 2019-07-18 12:00:00,000 login1 abc-def-geh 2019-07-18 12:00:00,001 login2 abc-def-geh,bcd-efg-hij

我正在尝试使用 sed(或任何其他 bash 文本处理工具)处理该文件以获得以下输出: 2019-07-18 12:00:00,000 login1 abc-def-geh 2019-07-18 12:00:00,001 login2 abc-def-geh 2019-07-18 12:00:00,001 login2 bcd-efg-hij

或者反过来:

  • 我需要捕获一行的一部分(从开始到登录信息)
  • 我需要在","上拆分该行的其余部分,以分隔ID
  • 每个新行都需要包含捕获的部分(日期时间登录)+ ID
awk '$NF~/,/{split($NF,a,",");$NF="";for(x in a)print $0a[x];next}7' file

这条线应该会有所帮助。


是的,最多可以有数百个这样的部件 (ID)

  • 它也会起作用。

Perl是实现目标的更慷慨的工具。试试这个:

perl -nle 'm/(.*) (S+) (S+)$/; print "$1 $2 $_" foreach split ",", $3'
sed ': c; s/^([^ ]+ [^ ]+ [^ ]+) ([^n,]+),(.*)/1 3n1 2/; t c; s/([^n]*)n(.*)/2n1/'
  • : c声明标签c("继续"中的简短助记符)
  • ^([^ ]+ [^ ]+ [^ ]+)- 匹配前三个部分
  • ([^n,]+)- 匹配第一部分直到逗号。找到换行符时也停止匹配,这在以后会很重要......
  • ,- 如果我们停在换行符处,我们应该停止处理。如果我们停在逗号处,我们应该匹配一个逗号。
  • (.*)- 记住逗号后面的其余部分。
  • 1 3n1 2- 在输入末尾添加匹配的部分。这样在下一次迭代中,我们可以再次匹配(一次又一次......我们停止 matchine,然后3它不再有任何逗号,那么([^n,]+),正则表达式部分将失败,因为不会有逗号。
  • t c- 如果上一个s///命令成功,则分支到标签cs///将成功,直到逗号在字符串中。
  • s/([^n]*)n(.*)/2n1/- 将第一行移动到最后一行。没有它,最后一个模式将是第一个。只需匹配第一行并移动它。

测试对象(随机键入以获取更多输入数据):

cat <<EOF |
2019-07-18 12:00:00,000 login1 abc-def-geh
2019-07-18 12:00:00,001 login2 abc-def-geh,bcd-efg-hij
2019-07-18 12:00:00,001 login2 abc-def-geh,bcd-efg-hij,bfdsabfasdh
2019-07-18 12:00:00,001 login2 abc-def-geh,bcd-efg-hij,bfdsabfasdh,fdsmfasfda,f,da,dfas,fd,asf,das,fsd,af,a,fdsafasdfsda,fasd
EOF
sed ': c; s/^([^ ]+ [^ ]+ [^ ]+) ([^n,]+),(.*)/1 3n1 2/; t c; s/([^n]*)n(.*)/2n1/'

将输出:

2019-07-18 12:00:00,000 login1 abc-def-geh
2019-07-18 12:00:00,001 login2 abc-def-geh
2019-07-18 12:00:00,001 login2 bcd-efg-hij
2019-07-18 12:00:00,001 login2 abc-def-geh
2019-07-18 12:00:00,001 login2 bcd-efg-hij
2019-07-18 12:00:00,001 login2 bfdsabfasdh
2019-07-18 12:00:00,001 login2 abc-def-geh
2019-07-18 12:00:00,001 login2 bcd-efg-hij
2019-07-18 12:00:00,001 login2 bfdsabfasdh
2019-07-18 12:00:00,001 login2 fdsmfasfda
2019-07-18 12:00:00,001 login2 f
2019-07-18 12:00:00,001 login2 da
2019-07-18 12:00:00,001 login2 dfas
2019-07-18 12:00:00,001 login2 fd
2019-07-18 12:00:00,001 login2 asf
2019-07-18 12:00:00,001 login2 das
2019-07-18 12:00:00,001 login2 fsd
2019-07-18 12:00:00,001 login2 af
2019-07-18 12:00:00,001 login2 a
2019-07-18 12:00:00,001 login2 fdsafasdfsda
2019-07-18 12:00:00,001 login2 fasd

请注意,在替换替换列表中使用 sed 内部的n是一个 gnu 扩展。

是的

...

sed可以做这种处理。使用(…)您可以在搜索模式中创建组,可以使用N替换访问这些组,其中N是组的编号。

如果最多可以有两个 ID,则sed命令很简单:

sed -E 's/(.*,.* )(.*),(.*)/12n13/'

。但

如果最后可以有多个ID,那么您将不得不摆弄sed的保持空间,因为您必须更换刚刚更换的部件。此时,切换到另一个工具更有意义。

$ awk '$NF~/,/{n=split($NF,p,/,/); sub(/[^[:space:]]+$/,""); for (i=1; i<=n; i++) print $0 p[i]; next} 1' file
2019-07-18 12:00:00,000 login1 abc-def-geh
2019-07-18 12:00:00,001 login2 abc-def-geh
2019-07-18 12:00:00,001 login2 bcd-efg-hij

此解决方案与@Kent解决方案之间的区别在于:

  1. 它不会导致 awk 为处理的行重新编译 $0(因此它不会更改字段之间的空格)。
  2. 这将导致 awk 将 $0 重新拆分为这些行的字段。
  3. 它将以与它们相同的顺序输出最后一个字段的各个部分 发生在输入中,而不是以"随机"(可能是哈希)顺序发生。

这可能对你有用(GNU sed):

sed -E 's/^(((S+s){3})[^,]*),/1n2/;P;D' file

将前三个字段后面的逗号替换为换行符,将前三个字段替换为打印、删除和重复。

最新更新