I have a text file where I want to replace all spaces inside [[
and ]]
with hyphens (brackets are never nested and always matched). The following is an example:
$ cat test.txt
abc [[foo]] xyz
abc [[foo bar]] xyz
abc [[foo bar baz]] xyz [[something else]]
So the desired output is:
abc [[foo]] xyz
abc [[foo-bar]] xyz
abc [[foo-bar-baz]] xyz [[something-else]]
I thought I could use sed
to match the string inside the brackets and then use the e
flag to run the result through sed
again to make the replacement. However the problem is that not only the matched string gets executed as a command, but the whole pattern space (which seems to be the entire line):
$ sed -E 's@(\[\[)(.+)(\]\])@sed -e "s/ /-/g" <<< "\1\2\3"@gpe' test.txt
abc sed -e "s/ /-/g" <<< "[[foo]]" xyz
sh: 1: Syntax error: redirection unexpected
abc sed -e "s/ /-/g" <<< "[[foo bar]]" xyz
sh: 1: Syntax error: redirection unexpected
abc sed -e "s/ /-/g" <<< "[[foo bar baz]]" xyz
sh: 1: Syntax error: redirection unexpected
Is there a way to limit what gets executed via the e
flag to the matched string? If not, how would I solve this problem with sed
?
Best Answer
I don't think there is a way to limit what's passed to the shell by the
e
modifier; however you could do something like this:Note that handling of multiple replacements is done via a loop - and due to the greediness of the match, it actually makes the substitutions in reverse order.
Note also that
e
uses/bin/sh
which will likely not support the<<<
input redirection (hence the use of the piped equivalentprintf "\2" | sed "s/ /-/g"
).If perl is an option you could do something closer to your original intent ex.:
Since perl provides a non-greedy modifier
?
, this can handle multiple replacements per line more conventionally using theg
flag on the outer substitution.