0

I have this simple dummy script called test1

#!/bin/sh
echo "Starting ..."

. ./test2.sh
bring_data

this_is_it

echo "...Done"`

`

It calls another script (note we are not spawning here, but sourcing)

#!/bin/sh

MY_DATA=\
   "john    road      usa
    adrian  avenue    nigeria
    arthur  street    brazil
    bill    roads     canada"

create_my_data() {
   echo "name = ${1}  type = ${2} country = ${3}"
   if [ "${2}" = "avenue" ]; then
     echo "failed... kick me out"
     exit 2
   fi
}

zombies_are() {
   printf "%s" "${1}" | while read -r guy_name lives_on country; do

     create_my_data "${guy_name}" "${lives_on}" "${country}"

   done
}

bring_data() {
  zombies_are "${MY_DATA}"
}

this_is_it() {
  echo "... more work has to be done..."
  sleep 1
  echo "..."
}

Since test1.sh is sourcing test2.sh... I would expect that calling exit 2 would terminate the whole scripting call. I would expect that calling that_is_it... to not happen... yet it does.

Is there something specific about this line: while read -r guy_name lives_on country; do

` which does not allow to exit completely from the call test1.sh ???

Here is the output at this point:

# ./test1.sh  
Starting ...
name = john  type = road country = usa
name = adrian  type = avenue country = nigeria
failed... kick me out
... more work has to be done...
... 
...Done

I changed the code to this...

`zombies_are "${MY_DATA}" || exit 2'

that works now.

  • 2
    the while loop is spawned in another subshell due to the pipe (`|`). the exit command exits this. you can try this out with this minimal script: `sh -c 'exit;echo hi'` vs `sh -c ':|exit;echo hi'` – Phu Ngo Dec 08 '22 at 17:49
  • Instead of `print ... | while read ...`, you can do `while read ... <<< $(printf ...)` (or use a heredoc) – William Pursell Dec 08 '22 at 18:01
  • 1
    Note that in order to use herestring, OP needs to change the shebang of `test1` to use `bash` or `zsh`... instead of `sh` – Phu Ngo Dec 08 '22 at 18:05
  • restricted to /bin/sh... thx – Chris Martin Dec 08 '22 at 18:56

2 Answers2

2

I change the code to this:

bring_data() { zombies_are "${MY_DATA}" || exit 2 }

1

The while loop is spawned in another subshell due to the pipe (|). The exit command exits this subshell. You can try this out with this minimal script: sh -c 'exit; echo hi', vs sh -c ': | exit; echo hi'.

A solution is to use process substitution instead to keep the while loop in the same shell:

zombies_are() {
   while read -r guy_name lives_on country; do

     create_my_data "${guy_name}" "${lives_on}" "${country}"

   done < <(printf "%s" "${1}")
}
Phu Ngo
  • 866
  • 11
  • 21
  • Process substitution works in bash script... Unfortunately, not whith shell script. Thx, it helped clarifying the problem (https://www.shellcheck.net/wiki/SC3001) – Chris Martin Dec 08 '22 at 18:55