1

In my answer here, I used the construct:

n=$1 shift

Reading Token Recognition spec, I understand that the shell will parse that line into two parts - the variable assignment n=$1 and the builtin command shift.

But the comments on my answer state that n=$1 shift does fail in some shells.

I spawned a quick check:

$ for shell in /bin/*[^c]sh; do
  printf '=%-17s=\n' "$shell"
  "$shell" -c 'a=$1 shift; echo "$a"' "$shell" 1
done
=/bin/ash         =
1
=/bin/bash        =

=/bin/dash        =
1
=/bin/heirloom-sh =
1
=/bin/ksh         =
1
=/bin/lksh        =
1
=/bin/mksh        =
1
=/bin/pdksh       =
1
=/bin/posh        =
1
=/bin/schily-osh  =
1
=/bin/schily-sh   =
1
=/bin/yash        =
1
=/bin/zsh         =

All shells, except bash and zsh, worked. But bash in posix mode and zsh in sh emulation do work, too:

$ ARGV0=sh bash -c 'a=$1 shift; echo "$a"' sh 1
1
$ ARGV0=sh zsh -c 'a=$1 shift; echo "$a"' sh 1 
1

Using var=value; shift worked in all shells.

So, are those constructs the same in POSIX-compliant shells?

cuonglm
  • 153,898
  • shift might be a special case. Try another builtin eg a=$1 let x=99;..., or a real command. (I remember many years ago having to go through all my scripts putting ; before shift when I first moved to bash). – meuh Mar 06 '16 at 19:17
  • This question is definitely not a duplicate of the other named question. – schily Mar 06 '16 at 21:30
  • See my recent answer for the other question that was incorrectly set up as duplicate to understand why both questions are completely different. If someone removes the duplicate tag, I could give a correct answer for this question too. – schily Mar 06 '16 at 21:40

1 Answers1

3

In the Bourne Shell, variable assignments before any kind of builtin command affects the whole shell.

As David Korn started to create an enhanced Bourne Shell with many builtins before he added history editing, it may have been obvious for him that this behavior is a problem.

As a result, ksh88 behaves different and this behavior has become the master for the newer POSIX standards.

The current rule is:

  • VAR=value before a special builtin affects the whole shell

  • VAR=value before any other commands only affect this command even in case this is a builtin command.

Your mistake was to run your tests with a special builtin.

If you like to get a list of special builtins, you may e.g. call builtin -s in the Schily Bourne Shell.

If you did your tests with a different builtin, e.g. with the cd command, you would have seen different results, as the variable assignment would only survive the cd command if the test was run on a classic Bourne Shell.

Note however that POSIX permits but does not require a shell to keep the environment with special builtins. If you like to get the same behavior for all builtins (even special builtins), you may prepend the name of the builtin by command.

schily
  • 19,173
  • As I interpreted, your answer is the same as what @Gilles said in other question. – cuonglm Mar 06 '16 at 22:03
  • It may be that this was amongst the long answer, but isn't is nice to answer a question with as few words as possible and the answer from @Gilles in the other question was not related to the other question. – schily Mar 06 '16 at 22:06