Home > Software engineering >  Bash corrupted echo for heredoc
Bash corrupted echo for heredoc

Time:04-14

Here my script:

#!/bin/bash

read -r -d '' content << VAR
one
two
three
{"foo":"bar"}
{cron":"0 1 * * *"}
VAR

for line in $content; do
  echo "==| ${line}"
done

without line {cron":"0 1 * * *"} it works perfectly and produces correct output:

==| one
==| two
==| three
==| {"foo":"bar"}

but with line {cron":"0 1 * * *"} it prints corrupted output:

==| one
==| two
==| three
==| {"foo":"bar"}
==| {cron":"0
==| 1
==| LICENSE
==| README.md
==| ed
==| y.sh
==| LICENSE
==| README.md
==| ed
==| y.sh
==| *"}

I'm running this script on macOS.

CodePudding user response:

The correct way to write this script is a while loop.

while IFS= read -r line; do
    printf '%s\n' "$line"
done <<'EOF'
one
two
three
{"foo":"bar"}
{cron":"0 1 * * *"}
EOF

At the very least, you don't need read to set the value of content:

content='one
two
three
{"foo":"bar"}
{cron":"0 1 * * *"}'

but iterating over a file using a for loop is full of problems. See How can I read a file (data stream, variable) line-by-line (and/or field-by-field)? and Why you don't read lines with "for"

CodePudding user response:

Edit: The correct way is to use a while-loop instead of a for-loop. See other answers.

The "for line"-loop splits at whitespace. The first unwanted whitespace is the space in cron line between "0" and "1". The "junk" in the output are the script's command line arguments? At least my tests look like they are.

To avoid splitting at whitespace, use the variable IFS. Set it to "newline".

IFS=$'\n'
read -r -d '' content << VAR
one
two
three
{"foo":"bar"}
{"cron":"0 1 * * *"}
VAR
for line in $content; do
  echo "==| ${line}"
done
  • Related