Is it possible to replace a command extracted by some regex with its output using sed?

For example, I have the next file:

2 + 2 = $$shell:echo 2 + 2 | bc$$ // and "some unescaped text' here

how I can transform it into:

2 + 2 = 4 // and "some unescaped text' here

I found that it is possible to extract the command and evaluate it:

echo '2 + 2 = $$shell:echo 2 + 2 | bc$$ // and "some unescaped text' here | sed -e 's/.*\$\$shell:\(.*\)\$\$.*/\1/e'

But I can't understand how to keep the rest part of the line.

  • sed it to echo "2 + 2 = $(echo 2 + 2 | bc)" then exec it. However with this type of thing you are opening a security hole. – ctrl-alt-delor Aug 29 at 18:39
  • A complete solution is probably not possible with only sed. As I understand, any solution leads to the creation of a string to evaluate in shell. So, I chose the solution in Perl as the answer... – Cyrill Sep 4 at 19:05

You could use Perl...

perl -pe 's[\$\$shell:(.*?)\$\$][ qx($1) =~ s/\n$//r ]ge' < inputfile

(qx is the equivalent of a command substitution, except it doesn't remove trailing newlines, so the =~ s/\n$//r does it. The surrounding s[][]ge is just a usual substitution with a Perl expression in the replacement.)

  • I'm unfamiliar with perl. But your example looks completely solving the problem (even with multiple commands per line, if '.*?' is used in the regex). Thank you. – Cyrill Aug 29 at 19:12

Ugly, but

$ echo '2 + 2 = $$shell:echo 2 + 2 | bc$$ // and some text here' | 
  sed -e 's/\(.*\)\$\$shell:\(.*\)\$\$\(.*\)/printf "%s%s%s\n" "\1" "$(sh -c "\2")" "\3"/e'
2 + 2 = 4 // and some text here
  • Thank you. I found new points about sed in your answer. But main purpose of using a such difficult pattern is to prevent the unexpected evaluation of '$(...)' and to avoid problems with escaping of non-command part of the line (it can contain quotas, for example). – Cyrill Aug 29 at 18:44

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.