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
=/bin/ash         =
=/bin/bash        =

=/bin/dash        =
=/bin/heirloom-sh =
=/bin/ksh         =
=/bin/lksh        =
=/bin/mksh        =
=/bin/pdksh       =
=/bin/posh        =
=/bin/schily-osh  =
=/bin/schily-sh   =
=/bin/yash        =
=/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
$ ARGV0=sh zsh -c 'a=$1 shift; echo "$a"' sh 1 

Using var=value; shift worked in all shells.

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

  • 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 6 '16 at 19:17
  • This question is definitely not a duplicate of the other named question. – schily Mar 6 '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 6 '16 at 21:40

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.

  • As I interpreted, your answer is the same as what @Gilles said in other question. – cuonglm Mar 6 '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 6 '16 at 22:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.