My idea is to convert the input file to a shell script in a form:
cat <<EOF$…EOF$
where …
is the original content of the input file, but with <pathname>
replaced by $(cat pathname)
, so when the script gets interpreted by a shell, it's a command substitution that will be replaced by the output of cat pathname
.
This is the command:
<example.txt sed ' s/[$\\`]/\\&/g s/<\([^<>]*\)>/$(\n$$\1\n)/g 1 i cat <<EOF$ $ a EOF$' | sed ' /^\$\$/ { s/[^$\\`]/\\&/g s/^\$\$/cat -- / }' | sh >example_processed.txt
Step by step:
<example.txt sed
–sed
readsexample.txt
and does the following:s/[$\\`]/\&/g
– escapes every$
,\
and`
, otherwise they would be special in our here document;s/<\([^<>]*\)>/$(\n$$\1\n)/g
– converts every string (not containing<
or>
, so non-greedily) between<
and>
to$($$string)
1 i cat <<EOF$
– insertscat <<EOF$
before the first line;$ a EOF$
– appendsEOF$
after the last line.
| sed
– the secondsed
reads from the first and/^\$\$/
– identifies lines starting with$$
(note they must come from the firstsed
because every$
from the original file is now preceded by a backslash) and there:s/[^$\\`]/\&/g
– every character but$
,\
or`
gets escaped by a backslash (the excluded characters are already escaped where appropriate)s/^\$\$/cat -- /
– and the leading$$
gets replaced bycat --
.
| sh >example_processed.txt
– POSIX shell interprets the resulting script and writes toexample_processed.txt
Your example file will get to sh
as the following script:
cat <<EOF$Some content containing $(cat -- \.\.\/\a\n\o\t\h\e\r\.\t\x\t) fileEOF$
Notes:
EOF$
is used instead of traditionalEOF
, so nothing in your original file can interfere. Even if there wasEOF$
in the original file, in the script it would beEOF\$
.- Newlines in pathnames are not supported,
<
and the corresponding>
must be in the same line of input for our code to work. - Other characters are supported. The pathname (
../another.txt
in the example) in the script is fully escaped (character by character), so even if you used a pathname with spaces, asterisks or whatever, it would be safe. $(…)
strips trailing newline characters, this is usually fine.--
is explained here: What does--
(double-dash) mean?- Relative paths in
<…>
will be resolved with respect to the working directory ofsh
, not to the directory containing the input file. In our example it's the same directory, but in general the directories may differ. If you want to resolve relative paths with respect to the directory of the input file then you must runsh
in this exact directory, just like we did.
The final result in example_processed.txt
:
Some content containing another file