4

Could someone please explain to me why my while loop seems to have an internal scope? I've seen multiple explanations online but they all have to do with pipes. My code has none.

The code:

#!/bin/sh
while read line
do
  echo "File contents: $line"
  echo
  if [ 1=1 ]; then
    test1=bob
  fi
  echo "While scope:"
  echo "  test1: $test1"
done < test.txt

if [ 1=1 ]; then
  test2=test2;
fi

echo;
echo "Script scope: "
echo "  test1: $test1"
echo "  test2: $test2"

The output:

File contents: In the file

While scope:
  test1: bob

Script scope:
  test1: 
  test2: test2
0

1 Answer 1

5

In the Bourne shell, redirecting a compound command (like your while loop) runs that compound command in a subshell.

In Solaris 10 and earlier1, you don't want to use /bin/sh as it's the Bourne shell. Use /usr/xpg4/bin/sh or /usr/bin/ksh instead to get a POSIX sh.

If for some reason you have to use /bin/sh, then to work around that, instead of doing:

compound-command < file

You can do:

exec 3<&0 < file
compound-command
exec <&3 3<&-

That is:

  1. duplicate the fd 0 onto fd 3 to save it away and then redirect fd 0 to the file.
  2. run the command
  3. restore fd 0 from the saved copy on fd 3. And close fd 3 which is no longer needed.

1. In Solaris 11 and later, Oracle eventually (at long last) made /bin/sh a POSIX shell, so it now behaves like the sh of most other Unices (it interprets the sh language specified by POSIX though it supports extensions over it as it's based on ksh88 (like other Unices, where sh is now generally based on ksh88, pdksh, bash, yash or an enhanced ash))

1
  • Ouch! that is one tricky shell. Jun 17, 2014 at 23:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .