其中有一个包含以下数据的日志文件:
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
反之亦然:
答案 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///
命令成功执行,则分支到标签c
。 s///
将成功,直到逗号成串为止。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之间的区别是:
答案 5 :(得分:0)
这可能对您有用(GNU sed):
sed -E 's/^(((\S+\s){3})[^,]*),/\1\n\2/;P;D' file
用换行符替换前三个字段后面的逗号,并打印,删除和重复前三个字段。