1

I would like to append multiple lines after a matched line in a text file in a bash script. While I don't particularly care what tool to choose for the job, the important thing to me is that I want to specify the lines appended "as is" inside the script (so without generating an additional file what would hold them) so they end up in a Bash variable, and without having to quote/escape anything in them - and for that purpose using a 'quoted' heredoc would work for me. Here is an example, appendtest.sh:

cat > mytestfile.txt <<'EOF'
    "'iceberg'"
    "'ice cliff'"
    "'ice field'"
    "'inlet'"
    "'island'"
    "'islet'"
    "'isthmus'"
EOF

IFS='' read -r -d '' REPLACER <<'EOF'
      "'$oasis$'"
      "'$ocean$'"
      "'$oceanic trench$'"
EOF

echo "$REPLACER"

sed -i "/    \"'ice field'\"/a${REPLACER}" mytestfile.txt

This unfortunately does not work:

$ bash appendtest.sh
      "'$oasis$'"
      "'$ocean$'"
      "'$oceanic trench$'"
sed: -e expression #1, char 39: unknown command: `"'

... because sed failed when an unescaped multiline replacement is used. So my question is:

  • What could I use instead of sed to perform matching on a line of text, and inserting/appending the lines as specified in the Bash variable ($REPLACER in the example)?
4

If you are using GNU sed, your best option is to use the r command:

sed -i "/    \"'ice field'\"/ r /dev/stdin" mytestfile.txt <<'EOF'
      "'$oasis$'"
      "'$ocean$'"
      "'$oceanic trench$'"
EOF
  • Oh, that looks great, I knew about r for reading files, but didn't think of using /dev/stdin - thanks @xhienne! – sdbbs Dec 17 '16 at 16:15
1

OK, found one way using perl:

cat > mytestfile.txt <<'EOF'
    "'iceberg'"
    "'ice cliff'"
    "'ice field'"
    "'inlet'"
    "'island'"
    "'islet'"
    "'isthmus'"
EOF

IFS='' read -r -d '' REPLACER <<'EOF'
      "'$oasis$'"
      "'$ocean$'"
      "'$oceanic trench$'"
EOF

# echo "$REPLACER"

IFS='' read -r -d '' LOOKFOR <<'EOF'
    "'ice field'"
EOF
export REPLACER # so perl can access it via $ENV
# -pi will replace in-place but not print to stdout; -p will only print to stdout:
perl -pi -e "s/($LOOKFOR)/"'$1$ENV{"REPLACER"}'"/" mytestfile.txt
# also, with export LOOKFOR, this works:
# perl -pi -e 's/($ENV{"LOOKFOR"})/$1$ENV{"REPLACER"}/' mytestfile.txt
cat mytestfile.txt # see if the replacement is done

Output is as desired:

$ bash appendtest.sh
    "'iceberg'"
    "'ice cliff'"
    "'ice field'"
      "'$oasis$'"
      "'$ocean$'"
      "'$oceanic trench$'"
    "'inlet'"
    "'island'"
    "'islet'"
    "'isthmus'"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.