我提前道歉,以防我忽略了解决问题的方法,但我花了几个小时试图解决这个问题:
我有一个日志文件,这是一个混乱[不是我的错T_T],我需要找到包含某些字符串的行。很好,很简单'直到这一点。一旦我找到它们,我需要替换单词“Before”[或String1]和“is”之间的每个空格[或String2,如果你愿意]使用不同的char [在我的情况下用下划线]。 “String1”之前或“String2”之后的任何内容都不会受到影响。
让你知道我应该做什么:
2012-08-27 00:14:55 1346019295409 Before Lorem ipsum dolor sit amet consectetuer Curabitur In id urna ut. Ut massa ac commodo commodo rutrum ac sit neque ante pede. is 47 ms
应该成为:
2012-08-27 00:14:55 1346019295409 Before_Lorem_ipsum_dolor_sit_amet_consectetuer_Curabitur_In_id_urna_ut._Ut_massa_ac_commodo_commodo_rutrum_ac_sit_neque_ante_pede._is 47 ms
由于几乎每个条目的时间戳都不同,我一直在考虑尝试找到一些方法来设置sed的限制,但没有运气......
有人可以指出我正确的方向吗?
答案 0 :(得分:2)
你可以。 Sed是Turing-complete,所以你可以用它做任何事情。这并不意味着sed是一个很好的工具:任何不能很好地映射到sed命令的东西都会很快变得复杂。如果你坚持使用sed:
:a
s/\( Before .*\) \(.* is \)/\1_\2/
t a
s/ Before \(.*\) is / Before_\1_is /
s/ Before is / Before_is /
我推荐使用awk。代码更长,但逻辑不那么令人头疼。
match($0, / Before (.* )?is /) {
prefix = substr($0, 1, RSTART + 6);
middle = substr($0, RSTART + 7, RLENGTH - 10);
suffix = substr($0, RSTART + RLENGTH - 3);
gsub(/ /, " ", middle);
$0 = prefix + middle + suffix;
}
答案 1 :(得分:2)
这可能适合你(GNU sed):
sed 's/ /_/4g;s/_\([^_]*\)_\([^_]*\)$/ \1 \2/' file
说明:
s/ /_/4g
从第4个空格开始用_
s/_\([^_]*\)_\([^_]*\)$/ \1 \2/'
用空格替换最后两个_
。另一种方法(可能更安全_
):
sed 's/\( [^ ]*\)\{2\}$/\n&/;h;s/\n.*//;s/ /_/4g;G;s/\n.*\n//' file
说明:
s/\( [^ ]*\)\{2\}$/\n&/
在最后两个空格之前插入换行符h
将模式空间(PS)复制到保留空间(HS)s/\n.*//
删除包含最后两个空格的模式。s/ /_/4g
用PS中的下划线替换除前四个空格以外的所有空格。G
将新行后跟HS的内容添加到PS。s/\n.*\n//
删除字符串的原始第一部分。答案 2 :(得分:1)
可能有一种更优雅的方式来做到这一点,但是有了sed,有很多版本,你或者可能没有最新版本的所有酷炫功能。
所以一个简单的解决方案,假设你对每一行有相同的格式,就是将前3个空格转换为制表符,一次一个,(这可能对你如何使用数据有利),然后将所有其他空格转换为'_'字符。
sed '
s/ / /
s/ / /
s/ / /
s/ /_/g' file > newFile
编辑,感谢David Yaw在行尾指出了所需的2个空格,我知道它不会那么容易:-)。所以..你可以将以下内容添加到上面的脚本中,再次依赖于你想要进行已知数量的替换的想法;在这里,我们找到最后的2个'_'字符并用空格替换它们,
'....
s/\([^_][^_]*\)_\([^_][^_]*\)$/\1 \2/
s/\([^_][^_]*\)_\([^_][^_]*\)$/\1 \2/' file > newFile
较新的sed可能不会尊重逃脱的抓住一群人;如果上述方法不起作用,请尝试从每一行中删除所有4'\'字符。
注意,当然,你必须做正确的事情才能在s / srchTarg / replPat /'的后半部分获得一个tab char作为替换模式。如果您使用的是vi编辑器,则Ctrl-V Ctrl-I(中间没有空格)将插入选项卡字符。当然,这意味着一个ControlV字符,(按住Ctrl键并按V键),然后按Ctrl I(再次按住Ctrl键,然后按I键)。如果你从基于Windows的编辑器复制粘贴,你可以假设选项卡字符被转换为空格,所以你必须自己解决这个问题。
另请注意,您可以使用其他一些字符而不是制表符,可能是':'或'|',最后一步是s/|/ /g
将它们转换回空格。
IHTH。
答案 3 :(得分:1)
使用Perl
尝试perl -ne '$_ =~ s/(?<=Before)(.*)(?=is)/$a=$1;$a=~s! !_!g; $a/e; print '
使用-e Perl调用执行单引号中的语句。 (?<=)
是积极的看法。它匹配它之后的一切。 (?=)
是一个正面的先行者。它匹配之前的一切。 (.*)
匹配两者之间的整个字符串,并以$ 1捕获匹配项。我将s///
与e
修饰符一起使用。这迫使Perl将/$a=$1;$a=~s! !_!g; $a
视为Perl代码并执行它。
只需尝试:
echo "2012-08-27 00:14:55 1346019295409 Before Lorem ipsum dolor sit amet consectetuer Curabitur In id urna ut. Ut massa ac commodo commodo rutrum ac sit ne que ante petryde. is 47 ms" |
perl -ne '$_ =~ s/(?<=Before)(.*)(?=is)/$a=$1;$a=~s! !_!g; $a/e; print '