我对bash / sed没什么问题。我需要能够在sed表达式中使用命令替换。我有两个大文本文件:
首先是logfile.txt,其中<strong>有时* 按ID显示错误消息(0xdeadbeef是常见示例),格式为ERRORID:0xdeadbeef
第二个errors.txt包含成对存储的错误消息LONG_ERROR_DESCRIPTION,0xdeadbeef
我试图使用sed和bash命令替换来完成任务:
cat logfile.txt | sed "s/ERRORID:\(0x[0-9a-f]*\)/ERROR:$(cat errors.txt |
grep \1 | grep -o '^[A-Z_]*' )/g"
(^^^当然应该在一行中)
如果它可行,那么我可以获得更好的错误信息的日志文件版本。
Lot's of meaningless stuff ERRORID:0xdeadbeef and something else =>
=> Lot's of meaningless stuff ERROR:LONG_ERROR_DESCRIPTION and something else
但事实并非如此。问题是sed无法将正则表达式部分(\ 1)“注入”命令替换。我还有什么其他选择?我知道可以先构建sed表达式或者以其他方式构建它,但我想避免多次解析这些文件(它们可能很大)。
总是非常感谢任何帮助。
*日志文件中没有真正的格式。不一致地使用部分,列,制表符/彗差分离
PS。只是解释一下。以下表达式有效,但当然没有任何参数传递:
echo "my cute cat" | sed "s/cat/$(echo dog)/g"
答案 0 :(得分:2)
您可以从错误消息目录创建sed脚本,然后将该sed脚本应用于日志文件。
基本上,这些内容如下:
sed 's/\(.*\), 0x\([0-9A-F]*\)$/s%ERRORID:0x\2%ERROR:\1%g/' errors.txt |
sed -f - logfile.txt
第一个sed脚本的输出应该是这样的:
s%ERRORID:0x00000001%ERROR:Out of memory%
s%ERRORID:0x00000002%ERROR:Stack overflow%
s%ERRORID:0x00000031%ERROR:values of beta may cause dom%
即,一个新的sed脚本,它指定了目录中每个错误代码的替换。
有各种不同的sed方言,所以这可能需要稍微调整一下。 Linux上的sed我认为应该在正则表达式中对括号进行分组之前使用反斜杠,并且很乐意容忍标准输入作为-f
选项的参数。但是这对其他Unices来说是不可移植的(但是如果你需要可移植性,你可以用Perl代替Perd)。
* 编辑:如果错误消息是相当静态的,并且/或者您想要从标准输入读取日志,请将生成的脚本保存在文件中;
# Do this once
sed 's/\(.*\), 0x\([0-9A-F]*\)$/s%ERRORID:0x\2%ERROR:\1%g/' errors.txt >errors.sed
# Use it many times
sed -f errors.sed logfile.txt
您还可以在#!/usr/bin/sed -f
及errors.sed
的顶部添加chmod +x
,以使其成为自包含的命令脚本。
答案 1 :(得分:1)
我不知道这是否有效,因为我无法得到关于捕获组是否仍然存在的答案,但是there is a lot more to sed than just the s
command。我以为你可以在正则表达式行选择器中使用捕获组,然后使用它来进行命令替换。像这样:
/ERRORID:\(0x[0-9a-f]*\)/ s/ERRORID:0x[0-9a-f]*/ERROR:$(grep \1 errors.txt | grep -o '^[A-Z_]*' )/
无论如何,如果这不起作用,我会改变方向,并指出这对Perl来说确实是一个好工作。以下是我将如何做到这一点,我认为它更清晰/更容易理解:
#!/usr/bin/perl
while(<>) {
while( /ERRORID:(0x[0-9a-f]*)/ ) {
$name = system("grep $1 errors.txt | grep -o '^[A-Z_]*'");
s/ERRORID:$1/ERROR:$name/g;
}
print;
}
然后执行:
./thatScript.pl logfile.txt
答案 2 :(得分:1)
使用gensub()的GNU awk和match()的3rg arg:
$ awk '
NR==FNR {
map[$NF] = gensub(/,[^,]+$/,"",1)
next
}
match($0,/(.*ERRORID:)(0x[[:xdigit:]]+)(.*)/,a) {
$0 = a[1] (a[2] in map ? map[a[2]] : a[2]) a[3]
}
1' errors.txt logfile.txt
Lot's of meaningless stuff ERRORID:LONG_ERROR_DESCRIPTION and something else =>
以上内容将比当前接受的答案中的sed脚本运行得快得多,并且不会因LONG_ERROR_DESCRIPTION
或%
或{{1 }},并且当给定的ERRORID是另一个子集的子集时也不会失败,例如如果&
和\1
是2个单独的错误代码,则sed脚本可能会失败,具体取决于它们在errors.txt中的显示顺序,例如他们可以将0xdead
转换为0xdeadbeef
。首先映射ERRORS:0xdeadbeef
。
答案 3 :(得分:0)
只是让人们寻找裸壳和sed的解决方案。不完美但工作:
cat logfile.txt | while read line ; do id=$(echo -E "$line" |
grep "ERRORID:0x[0-9a-f]*" | grep -o "0x[0-9a-f]*" ) ;
if [ ! -z "$id" ] ; then echo -E "$line" | sed "s/$id/$(grep $id errors.txt |
grep -o '^[A-Z_]*' )/g" ;else echo -E "$line" ; fi ; done
如果您看到一些修复选项,请分享。