Quantcast
Channel: User Kamil Maciorowski - Super User
Viewing all articles
Browse latest Browse all 656

Answer by Kamil Maciorowski for Linux shell command to replace path with file content

$
0
0

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 sedsed reads example.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$– inserts cat <<EOF$ before the first line;
    • $ a EOF$– appends EOF$ after the last line.
  • | sed– the second sed reads from the first and

    • /^\$\$/– identifies lines starting with $$ (note they must come from the first sed 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 by cat -- .
  • | sh >example_processed.txt– POSIX shell interprets the resulting script and writes to example_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 traditional EOF, so nothing in your original file can interfere. Even if there was EOF$ in the original file, in the script it would be EOF\$.
  • 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 of sh, 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 run sh in this exact directory, just like we did.

The final result in example_processed.txt:

Some content containing another file

Viewing all articles
Browse latest Browse all 656

Trending Articles