SED是否可以将此前缀= a,b,c,d拆分为该前缀= a \ n前缀= b \ n前缀= c

时间:2019-07-18 09:56:40

标签: 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

6 个答案:

答案 0 :(得分:1)

awk '$NF~/,/{split($NF,a,",");$NF="";for(x in a)print $0a[x];next}7' file

这一行应该有所帮助。


  

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

  • 它也会起作用。

答案 1 :(得分:1)

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

perl -nle 'm/(.*) (\S+) (\S+)$/; print "$1 $2 $_" foreach split ",", $3'

答案 2 :(得分:1)

sed ': c; s/^\([^ ]\+ [^ ]\+ [^ ]\+\) \([^\n,]\+\),\(.*\)/\1 \3\n\1 \2/; t c; s/\([^\n]*\)\n\(.*\)/\2\n\1/'
  • : c声明标签c(“ continue”中的简短助记符)
  • ^\([^ ]\+ [^ ]\+ [^ ]\+\)-匹配前三个部分
  • \([^\n,]\+\)-匹配第一部分,直到逗号为止。当找到换行符时也停止匹配,这将在以后变得很重要...
  • ,-如果我们在换行符处停止,则应停止处理。如果我们在逗号处停了,我们应该匹配一个逗号。
  • \(.*\)-记住逗号后的其余内容。
  • \1 \3\n\1 \2-将匹配的部分添加到输入的末尾。这样,在下一次迭代中,我们可以再次匹配(一次又一次...)。我们停止matchine,然后\3中不再有逗号,然后\([^\n,]\+\),正则表达式部分将失败,因为将不会有逗号。
  • t c-如果最后一个s///命令成功执行,则分支到标签cs///将成功,直到逗号成串为止。
  • s/\([^\n]*\)\n\(.*\)/\2\n\1/-将第一行移动到最后一行。没有它,最后的模式将是第一个。只需匹配第一行并移动它即可。

经过测试(随机输入以获取更多输入数据):

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 \3\n\1 \2/; t c; s/\([^\n]*\)\n\(.*\)/\2\n\1/'

将输出:

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扩展名。

答案 3 :(得分:0)

是的...

sed可以进行这种处理。使用(…)可以在搜索模式中创建组,可以使用\N替换其中的组,其中N是组号。

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

sed -E 's/(.*,.* )(.*),(.*)/\1\2\n\1\3/'

…但是

如果末尾可以有任意多个ID,那么您将不得不摆弄sed的保留空间,因为您将不得不替换刚刚替换的部分。那时,切换到其他工具更有意义。

答案 4 :(得分:0)

$ 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's solution之间的区别是:

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

答案 5 :(得分:0)

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

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

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