我有几个 sed 命令:提取相关信息
我的文件sample.log(格式为ncsa.log)如下所示:
2012_04_01_filename.log:29874:192.168.1.12 - - [16/Aug/2012:12:54:21 +0000] "GET /cxf/myservice01/v1/abc?anyparam=anything&anotherone=another HTTP/1.1" 200 3224 "-" "client name"
2012_04_01_filename.log:29874:192.168.1.12 - - [16/Aug/2012:12:54:25 +0000] "GET /cxf/myservice02/v1/XYZ?anyparam=anything&anotherone=another HTTP/1.1" 200 3224 "-" "client name"
2012_04_01_filename.log:29874:192.168.1.12 - - [16/Aug/2012:12:56:52 +0000] "GET /cxf/myservice01/v1/rsv/USER02?anyparam=anything&anotherone=another HTTP/1.1" 200 6456 "-" "client name"
2012_04_01_filename.log:29874:192.168.1.12 - - [16/Aug/2012:12:58:52 +0000] "GET /cxf/myservice01/v2/upr/USER01?anyparam=anything&anotherone=another HTTP/1.1" 200 2424 "-" "client name"
2012_04_01_filename.log:29874:192.168.1.12 - - [16/Aug/2012:12:59:11 +0000] "GET /cxf/myservice02/v1/xyz?anyparam=anything&anotherone=another HTTP/1.1" 200 233 "-" "client name"
这组管道 sed 正在提取我需要的 url 详细信息(第一个 sed:\1 = YYYY-MM-DD 中的日期,\2 = service0x,\3 = trigram,\4 = 可选实体 id,\5 = HTTP 响应代码, \6 = http 响应大小)
more sample.log | sed -r 's#^(...._.._..)_.*/cxf/(myservice.*)/v./(.{3})[/]*([a-Z0-9]*)?.*\sHTTP/1.1.\s(.{3})\s([0-9]*)\s.*#\1;\2;\L\3;\E\4;\5;\6#g' | sed -r 's!(.*;.*;.{3};)[a-Z0-9]+(;.*;.*)!\1retrieve\2!g' | sed -r 's!(.*);;(.*)!\1;list;\2!g' > request-by-operation.txt
需要的结果如下:
2012_04_01;myservice01;abc;list;200;3224
2012_04_01;myservice02;xyz;list;200;3224
2012_04_01;myservice01;rsv;retrieve;200;6456
2012_04_01;myservice01;upr;retrieve;200;2424
2012_04_01;myservice02;xyz;list;200;233
除了使用其他两个 sed 管道(完成这项工作)之外,我没有找到另一种方法来转换list
and操作。retrieve
我听说 sed 不支持替换部分(在特定组上)中的命令,#\1;\2;\L\3;\Eifnull(\4, "list", "retrieve");\5;\6#
但我想知道是否仍然可以仅使用一个 sed 命令以另一种方式完成此操作。
答案1
sed
无法调用替换部分中的命令,但它可以运行多个替换。在这种情况下,将所有替换都放在一个sed
似乎是可行的:
sed -r 's#^(...._.._..)_.*/cxf/(myservice.*)/v./(.{3})[/]*([a-Z0-9]*)?.*\sHTTP/1.1.\s(.{3})\s([0-9]*)\s.*#\1;\2;\L\3;\E\4;\5;\6#g;
s!(.*;.*;.{3};)[a-Z0-9]+(;.*;.*)!\1retrieve\2!g;
s!(.*);;(.*)!\1;list;\2!g'
答案2
您可以选择想要的部分,但也可以删除不需要的部分:
sed '
s|_[^_]* /[^/]*/|;|
s|/[^/]*/\(...\)|;\L\1|
s|?[^"]*" |;list;|
s|/.*;|;retrieve;|
s/ /;/
s/ .*$//'
答案3
GNU sed 确实有一个s///e
命令,但它发送的是所有的模式空间到 shell 进行评估:
$ echo "echo hello world" | sed 's/world/foo bar | rev/e'
rab oof olleh
所以“world”被“foo bar | rev”取代。模式空间现在是“echo hello foo bar | rev”。这被发送到 shell,输出被放置在模式空间中,然后隐式打印。
Perl 的e
标志允许您只关注字符串的匹配部分。
看https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-命令
e
该命令允许将 shell 命令的输入通过管道传送到模式空间。如果进行了替换,则执行在模式空间中找到的命令,并用其输出替换模式空间。尾随换行符被抑制;如果要执行的命令包含 null 字符,则结果未定义。这是一个 GNU sed 扩展。