7

Consider a simple sed script foo-to-bar.sed:

s/foo/bar/

and the simple invocation:

sed -f foo-to-bar.sed some-file.txt

Now, let's say I want to customize the replacement string (bar in this case) and pass it as an argument to the sed script. Is that possible?

NOTE: I'm aware that I can get rid of the sed script and use shell variables inline. I'm interested specifically about passing arguments into the sed script. I couldn't find anything in the documentation, but I still hope that I'm missing something.

1
  • 5
    You can't, there's no variables in sed, just commands.
    – cuonglm
    May 27, 2015 at 18:30

4 Answers 4

5

Since it seems like indeed there's no way to pass in arguments, the best workaround I can think of is to use an intermediate placeholder that is replaced from the command line. foo-to-bar.sed:

s/foo/#ARG1#/

Invocation:

sed -f foo-to-bar.sed -e "s/#ARG1#/bar/g" some-file.txt

Explanation: foo is first replaced with #ARG1# and then with bar passed from the command line. Note that it's important to have the -e after -f. Also there's nothing special about the # delimiter, use anything that wouldn't normally appear in the file.

1
  • 3
    If foo occurs 10.000 times in some-file.txt this will run 10.000 additional substitutions. You're better off altering the script: sed 's/#ARG1#/bar/' foo-to-bar.sed | sed -f - some-file.txt May 27, 2015 at 19:48
0

Yes you perfectly can! -
You can define a variable from the shell and escape the variable name inside the script something similar to this

s/'$replace'/bar/

then call the script as:

replace="foo" && sed -f script.sed

And if you want to pass the file as an argument the trick here is just having the script ending with no argument like this

/foo/{
  s/foo/bar/
}

Then from the shell just call it with xargs or find and let them to replace the argument for you:

find ./shelves -type f \( -name "*.json"  -o -name "*.csv" \) -print -exec sed -f main.sed {} \;

It works!

3
  • 1
    After several Google searches, this comment is the only reference I have found that claims that this can work, and when I followed your example, it did not work. Sep 4, 2020 at 18:26
  • My trick is really a trick or a work-around. sed scripts does not manage any argument, that's a fact. But here having a variable '$replace' outside the sed quotes is evaluated at shell level. So you can define the string to search in the replace variable and pipe in the same && pipe (otherwise it will fail) to the sed. IMHO this has to work: replace="foo" && echo "foo" | sed -n 's/'$replace'/bar/p'
    – Clement
    Sep 25, 2020 at 10:47
  • 1
    That's not gonna work (s/'$replace'/bar/ in a separate file). Only if you eval the script before passing it to sed.
    – x-yuri
    May 12, 2023 at 17:56
0

No good way, but I see workarounds. The best probably lies in using envsubst:

a.sed.tpl:

s/$s/x/

a.sh:

s=e
echo aoeu | sed -Ef <(cat a.sed.tpl | s=$s envsubst '$s')
$ bash -eu a.sh
aoxu

The value is passed as is. If you want to pass an arbitrary string and it being treated literally, you need to escape it before running sed.

There seems to be no way to escape $ with envsubst.

More options here.

0

You can pass an argument inside sed -- as long as you use double quotes for the sed code.

Try this exercise:

$ cat infile
Is it possible to pass arguments to a sed script?
$ fsed() { sed "s/pass/$1/g" "$2"; }
$ fsed PASS infile
Is it possible to PASS arguments to a sed script?
1
  • You also have to ensure that any & in the replacement is escaped and that any backslash preceding a digit is likewise escaped. With GNU sed, you would additionally have to care about various other escape sequences that have special meaning in the replacement string. You have also ignored the NOTE bit in the question.
    – Kusalananda
    May 12, 2023 at 22:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .