简体   繁体   中英

Bash corrupted echo for heredoc

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 .

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"

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM