3

This bash script writes an array to a file and then reads the file back into a different array. (This is useful for array-based communication between scripts.) However, a strange, non-reported error is trapped by the IFS line (line 12). Why?

#!/bin/bash

# eso-error-ic

trap 'echo Error trapped, with code $?, on line ${LINENO}' ERR

# write data to a file
arr=(0 abc) && printf "%s\n" "${arr[@]}" > eso.out

# read data from the file into an array
# throws an error!!
IFS=$'\n' read -d '' -a new_arr < eso.out

# but it worked...
echo ${new_arr[0]}
echo ${new_arr[1]}

Script output:

Error trapped, with code 1, on line 12
0
abc

What's missing is any sort of message displayed when the error is produced. All you get is the message from the trap but no message about what the error is.

In other words, the IFS/read line produces an error, which is trapped, but no error message is displayed and the line properly reads the file into an array variable. It works, reports no error, but an "error" is trapped.

If you comment out the trap line OR switch to the command/eval/cat approach to reading a file into an array (as suggested here), no error is trapped. Here is what the command/eval/cat line would look like for this script (to replace line 12):

IFS=$'\n' GLOBIGNORE='*' command eval 'new_arr=($(cat eso.out))'
DarkerIvy
  • 1,477
  • 14
  • 26
  • I can repro with Bash 3.2.57(1) on MacOS High Sierra with simply `read -d '' variable <<<"moo"; echo $?` – tripleee Feb 15 '18 at 13:28
  • Wow. Much simpler repo! I've reproduced it on Bash 4 on CentOS 6/7, RHEL 6/7, and Bash 3 & 4 on Apple Darwin 17.3 (High Sierra). – DarkerIvy Feb 15 '18 at 13:31
  • 1
    Cross site duplicate with detailed explanation : https://unix.stackexchange.com/questions/80045/read-a-array-d-n-foo-exit-code-1 – Aserre Feb 15 '18 at 13:38
  • 2
    By the way, `set -e` and/or ERR traps are generally considered a bad idea. See [BashFAQ #105](http://mywiki.wooledge.org/BashFAQ/105), skipping the allegory for the exercises below if in a hurry; or the list of incompatibilities between different shells' implementations of `set -e` (and, related, the extent to which its behavior isn't intuitively predictable) [here](https://www.in-ulm.de/~mascheck/various/set-e/). – Charles Duffy Feb 15 '18 at 14:13
  • Related question (identical cause) on this site: [Why does UNIX while read not read last line?](https://stackoverflow.com/questions/20010741/why-does-unix-while-read-not-read-last-line) – Charles Duffy Feb 15 '18 at 14:15
  • 1
    BTW, *in general*, I'd suggest `readarray -t new_arr – Charles Duffy Feb 15 '18 at 14:18
  • @CharlesDuffy the trouble with `readarray` is, it is not available on bash 4.4 on Apple, which is the platform I tend to test on before going to the server. Why? No idea. – DarkerIvy Feb 15 '18 at 20:00
  • @DarkerIvy, it's absolutely available with MacPorts or Homebrew builds of bash 4.4 on MacOS; I use it there all the time. I suspect that your script is instead being interpreted by the bash 3.2 that Apple shipped, and suggest running `echo $BASH_VERSION` *in the same shell interpreter context that generates any message about `readarray` not being available*. – Charles Duffy Feb 15 '18 at 20:30
  • @CharlesDuffy once again, you are absolutely right. shebang and profile pointing to two different versions. It _is_ available. – DarkerIvy Feb 15 '18 at 20:35

1 Answers1

6

The error comes from not receiving the delimiter that read was expecting. I get the same with

read -d x variable <<<"hello"

If I change the input to "hellox" the error disappears.

As mentioned by @Aserre, a detailed analys is at our Unix & Linux sister site and as pointed out by @CharlesDuffy a common workaround is

read variable || [[ $variable ]]

which is used even without -d to cope with files which might lack the final terminating newline.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • You can take the uncertainty out of this answer. It's spot-on, and is why `read x || [[ $x ]]` is an idiom when tolerating a missing delimiter is desired. – Charles Duffy Feb 15 '18 at 14:11
  • @tripleee Thanks for the explanation. I still say it is an error of the error to exit 1 without stderr-ing anything. – DarkerIvy Feb 15 '18 at 19:21