0

I hate asking this question, but Bash is fooling me again. Some days ago, the following SH file worked perfectly:

declare DONE=
declare -i i=0
until [ $DONE ]; do
    IFS= read -r line || DONE=1
    (( i++ ))
    echo "$line"
done < <( cat "$1" )

echo "$i lines!"

But today I get this error (passing a file as argument $1):

readline.sh: line 16: syntax error near unexpected token `<'
readline.sh: line 16: `done < <( cat "$1" )'

What has happened?

Andi
  • 457
  • 3
  • 19
  • 3
    It uses bash-only syntax. Start it with `bash`, not `sh`. And stop using that syntax; `done < <( cat "$1" )` is a needlessly inefficient alternative to `done <"$1"`. – Charles Duffy Nov 08 '20 at 15:07
  • This is also why putting a `.sh` extension on a bash script is a bad idea. – Charles Duffy Nov 08 '20 at 15:10
  • Of course I fooled myself. Thank you, @CharlesDuffy! – Andi Nov 08 '20 at 15:11
  • @CharlesDuffy I thought about this, although I have already seen so many non-executable Bash scripts with sh extension. – Andi Nov 08 '20 at 15:12
  • Your `DONE` variable is never updated, so it is a constant within the loop. Well overall always add a shebang to your shell script and make it executable. Use the shellcheck.net linter to help avoid many of the shell pitfalls. It is a good thing you script stopped to work as it revealed its brittleness. Broken code that seems to work is a hidden technical debt waiting for a disaster. – Léa Gris Nov 08 '20 at 15:13
  • By the way, the goal of this logic to to still output any trailing content without a newline after it? Consider `while IFS= read -r line || [[ $line ]]; do (( ++i )); printf '%s\n' "$line"; done` -- then you don't need any DONE variable at all. – Charles Duffy Nov 08 '20 at 15:24
  • @Andi, yes, using extensions on scripts is often done, but that doesn't make it a good idea. People do it because they saw it done, by people who did it because they saw it done... but the old-timers are over on the sidelines yelling "stop!". See f/e the history of the relevant factoid from the bash IRC channel at http://wooledge.org/~greybot/meta/.sh (the column on the left is UNIX time of each update). – Charles Duffy Nov 08 '20 at 15:28
  • @LéaGris, there's an assignment when `read` has a nonzero exit status. – Charles Duffy Nov 08 '20 at 15:29
  • @CharlesDuffy Sure, I just wanted to hear if there was _any_ reason to keep `.sh`, for example when handling files automatically. "By the way, the goal of this logic to to still output any trailing content without a newline after it?" Correct, it must output exactly what it gets (with the exception of '\0'). – Andi Nov 08 '20 at 15:48
  • @LéaGris "Well overall always add a shebang to your shell script and make it executable." I won't do the latter because there is a big difference having a library (with a collection of functions without a ~ 200x subprocess launch overhead) or a standalone executable. The library is sourced and never executed. – Andi Nov 08 '20 at 15:48
  • 1
    Ahh. If it's a library, then yes, have an extension -- but make it `.bash`. – Charles Duffy Nov 08 '20 at 15:50

0 Answers0