Replace a long string with the sed command: Argument list too long error

You could always do (since you're using GNU sed already (-i)):

sed -i -f - FILE_NAME << EOF
s/BASE_64/$BASE_64/g
EOF

-f - tells sed to read the sed script from stdin.

If you want to reuse the same script for several files, on Linux (and Linux only), with a shell like zsh, ksh and bash version up to 5.0 that implements here documents with temporary files (as opposed to pipes like dash or yash (or bash 5.1+) for relatively small heredocs and still with GNU sed, you could do:

find . -name '*.conf' -exec sed -i -f /dev/stdin {} + << EOF
s/BASE_64/$BASE_64/g
EOF

On Linux (and Linux and Cygwin only), /dev/stdin does not mean stdin in the same way - does. Instead, it's a symlink to the file open on stdin, so each time sed opens it, it opens the file anew from the start. The above command would work OK on other systems (that have /dev/stdin) or with shells that implement here-documents with pipes but only if there are few enough conf files that sed is called only once. When called the second time, on non-Linux/Cygwin systems, like with -f -, /dev/stdin would appear empty because it has already been read by the first invocation.

busybox sed also supports -i in the same way as GNU sed does, but does not support -f -. So you'd want to use -f /dev/stdin there in any case. With FreeBSD sed, use:

sed -i '' -f /dev/stdin FILE_NAME << EOF
s/BASE_64/$BASE_64/g
EOF

First, save the base64-encoded data in a file called, e.g., base64.txt.

For example:

base64 < originalfile > base64.txt

Then:

printf '%s\n' '/BASE64/r base64.txt' 1 '/BASE64/d' w | ed FILENAME

This uses ed to search in FILENAME for a line containing the string BASE64, insert the contents of base64.txt after that line, go back to the first line, then search for the line with string BASE64 again and delete it. The w command in ed saves the modified file.


Another option would be to replace sed with ed and store your commands in a file. For example, if you create ed_cmds with the following contents:

%s/BASE_64/<expanded variable>/g
w
q

you could then run

< ed_cmds ed FILE_NAME

and it would make the changes you wanted, so instead of setting $BASE_64 you'd create the ed command file.

Ed Explanation

  • % means to apply the command to each line of the file
  • s/pat1/pat2/g substitutes occurrences of pat1 with pat2 and g at the end makes it do it for every match on the line, not just the first
  • w write the changes to disk
  • q quit (which would happen when it got EOF anyway)

Of course, you could put your sed commands in a file and use -f as well, but if you're doing that and you want to modify the file in place you might as well use ed instead of creating a temporary file and moving it as sed -i does.