Is test or [ or [[ more portable both between bash shells and between other shells?

Yes, there are differences. The most portable are test or [ ]. These are both part of the POSIX test specification.

The if ... fi construct is also defined by POSIX and should be completely portable.

The [[ ]] is a ksh feature that is also present in some versions of bash (all modern ones), in zsh and perhaps in others but is not present in sh or dash or the various other simpler shells.

So, to make your scripts portable, use [ ], test or if ... fi.


[ is synonym of the test command and it is simultaneously a bash builtin and separate command. But [[ is a bash keyword and works in some versions only. So for reasons of portability you are better off using single [] or test

[ -w "/home/durrantm" ] && echo "writable"

Please note, that [] && cmd is not the same as if .. fi construction.

Sometimes its behaviour its pretty similar and you can use [] && cmd instead of if .. fi. But only sometimes. If you have more then one command to execute if condition or you need if .. else .. fi be careful and whatch the logic.

A couple of examples:

[ -z "$VAR" ] && ls file || echo wiiii

Is not the same as

if [ -z $VAR ] ; then
  ls file
else
  echo wiii
fi

because if ls will fail, echo will be executed which will not happen with if.

Another example:

[ -z "$VAR" ] && ls file && echo wiii

is not the same as

if [ -z "$VAR" ] ; then
   ls file
   echo $wiii
fi

though this construction will act the same

[ -z "$VAR" ] && { ls file ; echo wiii ; }

please note ; after echo is important and must be there.

So resuming statement above we can say

[] && cmd == if first command is successful then execute the next one

if .. fi == if condition (which may be the test command as well) then execute command(s)

So for portability between [ and [[ use [ only.

if is POSIX compatible. So if you have to choose between [ and if choose looking at your task and expected behaviour.