来自终端的 Sed 正则表达式字符串替换
Sed regex string substitution from terminal
我有一个标准格式的日志文件,例如:
31 Mar - Lorem Ipsom1
31 Mar - Lorem Ipsom2
31 Mar - Lorem Ipsom3
我要实现的替换是 31*31 到 31,所以我将得到一个只有最后一行的日志,在这个例子中它看起来像:
31 Mar - Lorem Ipsom3
我希望在没有 perl 的定制 linux 机器上执行它。
我试过像这样使用 sed:
sed -i -- 's/31*31/31/g' /var/log/prog/logFile
但它什么也没做..
也欢迎任何涉及 ninja bash 命令的替代方法。
*
不像在 shell 中那样是通配符,它是一个量词。您需要对 .
(任何字符)进行量化。因此正则表达式是:
sed ':a;N;$!ba;s/31.*31/31/g'
(我删除了 -i
标志,以便您可以先安全地测试您的文件)。
:a;N;$!ba;
部分可以处理超过 新行。
但请注意:
正则表达式将匹配任何 31
所以:
31 Mar - Lorem Ipsom1
31 Mar - Lorem 31 Ipsom2
会导致
31 Ipsom2
会贪心匹配,如果log是这样写的:
31 Mar - Lorem Ipsom1
30 Mar - Lorem Ipsom2
31 Mar - Lorem Ipsom3
它删除第二行。
你可以这样写来解决第一个问题:
sed ':a;N;$!ba;s/(^|\n)31.*\n31/31/g'
这会强制正则表达式第二个 31
位于行的 开头 。
一种仅保留与模式匹配的连续行的最后一行的方法是
sed -n '/^31/ { :a $!{ h; n; //ba; x; G } }; p' filename
其工作原理如下:
/^31/ { # if a line begins with 31
:a # jump label for looping
$!{ # if the end of input has not been reached (otherwise the current
# line is the last line of the block by virtue of being the last
# line)
h # hold the current line
n # fetch the next line. (note that this doesn't print the line
# because of -n)
//ba # if that line also begins with 31, go to :a. // attempts the
# most recently attempted regex again, which was ^31
x # swap hold buffer, pattern space
G # append hold buffer to pattern space. The PS now contains
# the last line of the block followed by the first line that
# comes after it
}
}
p # in the end, print the result
这避免了多行正则表达式的一些问题,例如匹配在一行中间开始或结束。它也不会丢弃两个匹配行块之间的行并保留每个块的最后一行。
我想您可能正在寻找 "tail" 来获取文件的最后一行
例如
tail -1 /path/file
或者如果您想要每天的最后一个条目,那么 "sort" 可能是您的解决方案
sort -ur -k 1,2 /path/file | sort
-u
标志指定仅返回一个匹配的关键字段
-
-k 1,2
指定关键字段是前两个字段 - 在这种情况下它们是月份和日期 - 默认情况下字段由白色分隔 space.
-
-r
标志反转行,以便返回每个日期的最后一个匹配项。第二次排序恢复原顺序
如果您的日志文件有超过一个月的数据,并且您希望保留顺序(例如,如果您在同一个文件中有 3 月 31 日和 4 月 1 日),您可以尝试:
cat -n tmp2 | sort -nr | sort -u -k 2,3 | sort -n | cut -f 2-
cat -n
在排序前将行号添加到日志文件中。
sort
和以前一样,但使用字段 2 和 3,因为字段 1 现在是原始行号
sort
按原行号恢复原顺序
- 使用
cut
去掉行号,恢复原来的行内容。
例如
$ cat tmp2
30 Mar - Lorem Ipsom2
30 Mar - Lorem Ipsom1
31 Mar - Lorem Ipsom1
31 Mar - Lorem Ipsom2
31 Mar - Lorem Ipsom3
1 Apr - Lorem Ipsom1
1 Apr - Lorem Ipsom2
$ cat -n tmp2 | sort -r | sort -u -k 2,3 | sort | cut -f 2-
30 Mar - Lorem Ipsom1
31 Mar - Lorem Ipsom3
1 Apr - Lorem Ipsom2
我有一个标准格式的日志文件,例如:
31 Mar - Lorem Ipsom1
31 Mar - Lorem Ipsom2
31 Mar - Lorem Ipsom3
我要实现的替换是 31*31 到 31,所以我将得到一个只有最后一行的日志,在这个例子中它看起来像:
31 Mar - Lorem Ipsom3
我希望在没有 perl 的定制 linux 机器上执行它。 我试过像这样使用 sed:
sed -i -- 's/31*31/31/g' /var/log/prog/logFile
但它什么也没做.. 也欢迎任何涉及 ninja bash 命令的替代方法。
*
不像在 shell 中那样是通配符,它是一个量词。您需要对 .
(任何字符)进行量化。因此正则表达式是:
sed ':a;N;$!ba;s/31.*31/31/g'
(我删除了 -i
标志,以便您可以先安全地测试您的文件)。
:a;N;$!ba;
部分可以处理超过 新行。
但请注意:
正则表达式将匹配任何
31
所以:31 Mar - Lorem Ipsom1 31 Mar - Lorem 31 Ipsom2
会导致
31 Ipsom2
会贪心匹配,如果log是这样写的:
31 Mar - Lorem Ipsom1 30 Mar - Lorem Ipsom2 31 Mar - Lorem Ipsom3
它删除第二行。
你可以这样写来解决第一个问题:
sed ':a;N;$!ba;s/(^|\n)31.*\n31/31/g'
这会强制正则表达式第二个 31
位于行的 开头 。
一种仅保留与模式匹配的连续行的最后一行的方法是
sed -n '/^31/ { :a $!{ h; n; //ba; x; G } }; p' filename
其工作原理如下:
/^31/ { # if a line begins with 31
:a # jump label for looping
$!{ # if the end of input has not been reached (otherwise the current
# line is the last line of the block by virtue of being the last
# line)
h # hold the current line
n # fetch the next line. (note that this doesn't print the line
# because of -n)
//ba # if that line also begins with 31, go to :a. // attempts the
# most recently attempted regex again, which was ^31
x # swap hold buffer, pattern space
G # append hold buffer to pattern space. The PS now contains
# the last line of the block followed by the first line that
# comes after it
}
}
p # in the end, print the result
这避免了多行正则表达式的一些问题,例如匹配在一行中间开始或结束。它也不会丢弃两个匹配行块之间的行并保留每个块的最后一行。
我想您可能正在寻找 "tail" 来获取文件的最后一行 例如
tail -1 /path/file
或者如果您想要每天的最后一个条目,那么 "sort" 可能是您的解决方案
sort -ur -k 1,2 /path/file | sort
-u
标志指定仅返回一个匹配的关键字段-
-k 1,2
指定关键字段是前两个字段 - 在这种情况下它们是月份和日期 - 默认情况下字段由白色分隔 space. -
-r
标志反转行,以便返回每个日期的最后一个匹配项。第二次排序恢复原顺序
如果您的日志文件有超过一个月的数据,并且您希望保留顺序(例如,如果您在同一个文件中有 3 月 31 日和 4 月 1 日),您可以尝试:
cat -n tmp2 | sort -nr | sort -u -k 2,3 | sort -n | cut -f 2-
cat -n
在排序前将行号添加到日志文件中。sort
和以前一样,但使用字段 2 和 3,因为字段 1 现在是原始行号sort
按原行号恢复原顺序- 使用
cut
去掉行号,恢复原来的行内容。
例如
$ cat tmp2
30 Mar - Lorem Ipsom2
30 Mar - Lorem Ipsom1
31 Mar - Lorem Ipsom1
31 Mar - Lorem Ipsom2
31 Mar - Lorem Ipsom3
1 Apr - Lorem Ipsom1
1 Apr - Lorem Ipsom2
$ cat -n tmp2 | sort -r | sort -u -k 2,3 | sort | cut -f 2-
30 Mar - Lorem Ipsom1
31 Mar - Lorem Ipsom3
1 Apr - Lorem Ipsom2