$ cat sample.dmesg.log | sed -re 's/(READ block )([0-9]+)( on xvda3.*$)/\1\2\3 XXX/g'
[ 6031.953619] sysctl(20774): READ block 5285528 on xvda3 (32 sectors) XXX
[ 6031.954317] sysctl(20774): READ block 5285768 on xvda3 (8 sectors) XXX
[ 6031.954598] sysctl(20774): READ block 5285648 on xvda3 (120 sectors) XXX
[ 6031.954617] sysctl(20774): READ block 5285776 on xvda3 (24 sectors) XXX
[ 6031.955482] sysctl(20774): READ block 5285560 on xvda3 (88 sectors) XXX
[ 6031.955699] sysctl(20774): READ block 4473568 on xvda3 (8 sectors) XXX
[ 6031.955730] sysctl(20774): READ block 4473584 on xvda3 (16 sectors) XXX
[ 6031.955787] sysctl(20774): READ block 4749496 on xvda3 (224 sectors) XXX

For each input line, I want to replace the XXX above with the result of running the command ./showblock NUMBER, where NUMBER is \2 (second group) in the above sed eg. 5285528

But how can I find, execute a program, then replace/modify at the same time?

Sample result:

[ 6031.953619] sysctl(20774): READ block 5285528 on xvda3 (32 sectors) Path: /usr/lib64/libgpg-error.so.0.24.2

Hopefully this can this be done with the same sed command; or some other one command?

If someone knows how else to rephrase this question so that it's more generic and useful, please do so.

In other words: How to execute external program in the middle of the regex/regexp match ?


Try perl:

perl -pe '
    s{(READ block) (\d+) (on xvda3.*$)}
     {join " ",$1, $2, $3, qx(./showblock $2)}e
' sample.dmesg.log

To remove the trailing newline, you could do

     { chomp($out = qx(./showblock $2)); join " ", $1, $2, $3, $out }e
  • Impressive! Do you know if sed has this capability? (to execute command) I'll assume it doesn't. – Marcus Linsner Sep 6 '18 at 19:29
  • 1
    @MarcusLinsner - only gnu sed can do that via the e flag... – don_crissti Sep 6 '18 at 19:33
  • There seems to be an implied newline added when replacing, other than the one that ./showblock outputs. I think maybe join adds one ? Can I remove that? ie. I'm getting a blank line after each replaced line. – Marcus Linsner Sep 6 '18 at 19:37
  • 1
    the output from qx(...) includes a trailing newline, and the current line already has one. – glenn jackman Sep 6 '18 at 20:11
  • I was looking the s modifier to match the current line's newline(aka \n, aka $) via the ., so the }e above becomes }es and the .*(any char(including the new line char, now) for 0 or more times) becomes [^\$]*(any char that's not end of line, for 0 or more times. Note: I had to escape $ within those [ ] parens). Now I can allow the output of qx(...) to contain the new line instead. – Marcus Linsner Sep 7 '18 at 23:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.