Skip to main content
Use test -x; test -e is not portable, and -x also tests for execute permissions.
Source Link
Kaz
  • 8.9k
  • 2
  • 31
  • 52

Today, you can usually find a POSIX shell on a system, and so that generally means you can script in the POSIX language (modulo running into compliance bugs).

The only problem is that /bin/sh is sometimes not a POSIX shell. And you must hard-code the #! line into scripts that are to behave as nice executables; you can't just ask the user to research the problem and then invoke your script as /path/to/posix/shell myscript.

So, the trick is to use POSIX features in your script, but make the script automatically find the POSIX shell. One way to do it is like this:

#!/bin/sh

# At this point, we may be running under some old shell
# we have to tread carefully.

# note how we use test rather than [ ] syntax and avoid
# depending on test with no argument producing a failure;
# i.e. "test $posix_shell".

if ! test x$posix_shell = x ; then
  # the three possible shell paths are just an example;
  # please extend as necessary.

  for shell in /usr/xpg4/bin/sh /bin/bash /usr/bin/bash ; do
    if test -ex $shell ; then
       posix_shell=$shell
    fi
  done
  if test x$posix_shell = x ; then
    echo "no POSIX shell found"
    exit 1
    # or we could avoid bailing here and just fall back on /bin/sh:
    # echo "falling back on /bin/sh: cross your fingers that it works"
    # posix_shell=/bin/sh
  fi
  export posix_shell

  # plain "$@" is broken in ancient shells! 
  # I seem to recall ${@+"$@"}: not sure if that's the right trick.

  exec $posix_shell $0 ${@+"$@"}  # can we count on exec in legacy shells? 
fi

# phew, at this point in the script we have been re-executed and are
# being interpreted by some reasonably modern shell. We can use $(...)
# command substitution, and other features.

There are other approaches, such as code generation. Boostrap your scripts with a small script that takes a body of script files without a #! line, and adds one.

The worst possible thing you can do is to start writing entire scripts in such a way that they run on a Bourne shell from 1981. This is only necessary if you must write for a system that doesn't really doesn't have any other shell.

Today, you can usually find a POSIX shell on a system, and so that generally means you can script in the POSIX language (modulo running into compliance bugs).

The only problem is that /bin/sh is sometimes not a POSIX shell. And you must hard-code the #! line into scripts that are to behave as nice executables; you can't just ask the user to research the problem and then invoke your script as /path/to/posix/shell myscript.

So, the trick is to use POSIX features in your script, but make the script automatically find the POSIX shell. One way to do it is like this:

#!/bin/sh

# At this point, we may be running under some old shell
# we have to tread carefully.

# note how we use test rather than [ ] syntax and avoid
# depending on test with no argument producing a failure;
# i.e. "test $posix_shell".

if ! test x$posix_shell = x ; then
  # the three possible shell paths are just an example;
  # please extend as necessary.

  for shell in /usr/xpg4/bin/sh /bin/bash /usr/bin/bash ; do
    if test -e $shell ; then
       posix_shell=$shell
    fi
  done
  if test x$posix_shell = x ; then
    echo "no POSIX shell found"
    exit 1
    # or we could avoid bailing here and just fall back on /bin/sh:
    # echo "falling back on /bin/sh: cross your fingers that it works"
    # posix_shell=/bin/sh
  fi
  export posix_shell

  # plain "$@" is broken in ancient shells! 
  # I seem to recall ${@+"$@"}: not sure if that's the right trick.

  exec $posix_shell $0 ${@+"$@"}  # can we count on exec in legacy shells? 
fi

# phew, at this point in the script we have been re-executed and are
# being interpreted by some reasonably modern shell. We can use $(...)
# command substitution, and other features.

There are other approaches, such as code generation. Boostrap your scripts with a small script that takes a body of script files without a #! line, and adds one.

The worst possible thing you can do is to start writing entire scripts in such a way that they run on a Bourne shell from 1981. This is only necessary if you must write for a system that doesn't really doesn't have any other shell.

Today, you can usually find a POSIX shell on a system, and so that generally means you can script in the POSIX language (modulo running into compliance bugs).

The only problem is that /bin/sh is sometimes not a POSIX shell. And you must hard-code the #! line into scripts that are to behave as nice executables; you can't just ask the user to research the problem and then invoke your script as /path/to/posix/shell myscript.

So, the trick is to use POSIX features in your script, but make the script automatically find the POSIX shell. One way to do it is like this:

#!/bin/sh

# At this point, we may be running under some old shell
# we have to tread carefully.

# note how we use test rather than [ ] syntax and avoid
# depending on test with no argument producing a failure;
# i.e. "test $posix_shell".

if ! test x$posix_shell = x ; then
  # the three possible shell paths are just an example;
  # please extend as necessary.

  for shell in /usr/xpg4/bin/sh /bin/bash /usr/bin/bash ; do
    if test -x $shell ; then
       posix_shell=$shell
    fi
  done
  if test x$posix_shell = x ; then
    echo "no POSIX shell found"
    exit 1
    # or we could avoid bailing here and just fall back on /bin/sh:
    # echo "falling back on /bin/sh: cross your fingers that it works"
    # posix_shell=/bin/sh
  fi
  export posix_shell

  # plain "$@" is broken in ancient shells! 
  # I seem to recall ${@+"$@"}: not sure if that's the right trick.

  exec $posix_shell $0 ${@+"$@"}  # can we count on exec in legacy shells? 
fi

# phew, at this point in the script we have been re-executed and are
# being interpreted by some reasonably modern shell. We can use $(...)
# command substitution, and other features.

There are other approaches, such as code generation. Boostrap your scripts with a small script that takes a body of script files without a #! line, and adds one.

The worst possible thing you can do is to start writing entire scripts in such a way that they run on a Bourne shell from 1981. This is only necessary if you must write for a system that doesn't really doesn't have any other shell.

added 180 characters in body
Source Link
Kaz
  • 8.9k
  • 2
  • 31
  • 52

Today, you can usually find a POSIX shell on a system, and so that generally means you can script in the POSIX language (modulo running into compliance bugs).

The only problem is that /bin/sh is sometimes not a POSIX shell. And you must hard-code the #! line into scripts that are to behave as nice executables; you can't just ask the user to research the problem and then invoke your script as /path/to/posix/shell myscript.

So, the trick is to use POSIX features in your script, but make the script automatically find the POSIX shell. One way to do it is like this:

#!/bin/sh

# At this point, we may be running under some old shell
# we have to tread carefully.

# note how we use test rather than [ ] syntax and avoid
# depending on test with no argument producing a failure;
# i.e. "test $posix_shell".

if ! test x$posix_shell = x ; then
  # the three possible shell paths are just an example;
  # please extend as necessary.

  for shell in /usr/xpg4/bin/sh /bin/bash /usr/bin/bash ; do
    if test -e $shell ; then
       posix_shell=$shell
    fi
  done
  if test x$posix_shell = x ; then
    echo "no POSIX shell found"
    exit 1
    # or we could avoid bailing here and just fall back on /bin/sh:
    # echo "falling back on /bin/sh: cross your fingers that it works"
    # posix_shell=/bin/sh
  fi
  export posix_shell

  # plain "$@" is broken in ancient shells! 
  # I seem to recall ${@+"$@"}: not sure if that's the right trick.

  exec $posix_shell $0 ${@+"$@"}  # can we count on exec in legacy shells? 
fi

# phew, at this point in the script we have been re-executed and are
# being interpreted by some reasonably modern shell. We can use $(...)
# command substitution, and other features.

There are other approaches, such as code generation. Boostrap your scripts with a small script that takes a body of script files without a #! line, and adds one.

The worst possible thing you can do is to start writing entire scripts in such a way that they run on a Bourne shell from 1981. This is only necessary if you must write for a system that doesn't really doesn't have any other shell.

Today, you can usually find a POSIX shell on a system, and so that generally means you can script in the POSIX language (modulo running into compliance bugs).

The only problem is that /bin/sh is sometimes not a POSIX shell. And you must hard-code the #! line into scripts that are to behave as nice executables; you can't just ask the user to research the problem and then invoke your script as /path/to/posix/shell myscript.

So, the trick is to use POSIX features in your script, but make the script automatically find the POSIX shell. One way to do it is like this:

#!/bin/sh

# At this point, we may be running under some old shell
# we have to tread carefully.

# note how we use test rather than [ ] syntax and avoid
# depending on test with no argument producing a failure;
# i.e. "test $posix_shell".

if ! test x$posix_shell = x ; then
  # the three possible shell paths are just an example;
  # please extend as necessary.

  for shell in /usr/xpg4/bin/sh /bin/bash /usr/bin/bash ; do
    if test -e $shell ; then
       posix_shell=$shell
    fi
  done
  if test x$posix_shell = x ; then
    echo "no POSIX shell found"
    exit 1
  fi
  export posix_shell

  # plain "$@" is broken in ancient shells! 
  # I seem to recall ${@+"$@"}: not sure if that's the right trick.

  exec $posix_shell $0 ${@+"$@"}  # can we count on exec in legacy shells? 
fi

# phew, at this point in the script we have been re-executed and are
# being interpreted by some reasonably modern shell. We can use $(...)
# command substitution, and other features.

There are other approaches, such as code generation. Boostrap your scripts with a small script that takes a body of script files without a #! line, and adds one.

The worst possible thing you can do is to start writing entire scripts in such a way that they run on a Bourne shell from 1981. This is only necessary if you must write for a system that doesn't really doesn't have any other shell.

Today, you can usually find a POSIX shell on a system, and so that generally means you can script in the POSIX language (modulo running into compliance bugs).

The only problem is that /bin/sh is sometimes not a POSIX shell. And you must hard-code the #! line into scripts that are to behave as nice executables; you can't just ask the user to research the problem and then invoke your script as /path/to/posix/shell myscript.

So, the trick is to use POSIX features in your script, but make the script automatically find the POSIX shell. One way to do it is like this:

#!/bin/sh

# At this point, we may be running under some old shell
# we have to tread carefully.

# note how we use test rather than [ ] syntax and avoid
# depending on test with no argument producing a failure;
# i.e. "test $posix_shell".

if ! test x$posix_shell = x ; then
  # the three possible shell paths are just an example;
  # please extend as necessary.

  for shell in /usr/xpg4/bin/sh /bin/bash /usr/bin/bash ; do
    if test -e $shell ; then
       posix_shell=$shell
    fi
  done
  if test x$posix_shell = x ; then
    echo "no POSIX shell found"
    exit 1
    # or we could avoid bailing here and just fall back on /bin/sh:
    # echo "falling back on /bin/sh: cross your fingers that it works"
    # posix_shell=/bin/sh
  fi
  export posix_shell

  # plain "$@" is broken in ancient shells! 
  # I seem to recall ${@+"$@"}: not sure if that's the right trick.

  exec $posix_shell $0 ${@+"$@"}  # can we count on exec in legacy shells? 
fi

# phew, at this point in the script we have been re-executed and are
# being interpreted by some reasonably modern shell. We can use $(...)
# command substitution, and other features.

There are other approaches, such as code generation. Boostrap your scripts with a small script that takes a body of script files without a #! line, and adds one.

The worst possible thing you can do is to start writing entire scripts in such a way that they run on a Bourne shell from 1981. This is only necessary if you must write for a system that doesn't really doesn't have any other shell.

Source Link
Kaz
  • 8.9k
  • 2
  • 31
  • 52

Today, you can usually find a POSIX shell on a system, and so that generally means you can script in the POSIX language (modulo running into compliance bugs).

The only problem is that /bin/sh is sometimes not a POSIX shell. And you must hard-code the #! line into scripts that are to behave as nice executables; you can't just ask the user to research the problem and then invoke your script as /path/to/posix/shell myscript.

So, the trick is to use POSIX features in your script, but make the script automatically find the POSIX shell. One way to do it is like this:

#!/bin/sh

# At this point, we may be running under some old shell
# we have to tread carefully.

# note how we use test rather than [ ] syntax and avoid
# depending on test with no argument producing a failure;
# i.e. "test $posix_shell".

if ! test x$posix_shell = x ; then
  # the three possible shell paths are just an example;
  # please extend as necessary.

  for shell in /usr/xpg4/bin/sh /bin/bash /usr/bin/bash ; do
    if test -e $shell ; then
       posix_shell=$shell
    fi
  done
  if test x$posix_shell = x ; then
    echo "no POSIX shell found"
    exit 1
  fi
  export posix_shell

  # plain "$@" is broken in ancient shells! 
  # I seem to recall ${@+"$@"}: not sure if that's the right trick.

  exec $posix_shell $0 ${@+"$@"}  # can we count on exec in legacy shells? 
fi

# phew, at this point in the script we have been re-executed and are
# being interpreted by some reasonably modern shell. We can use $(...)
# command substitution, and other features.

There are other approaches, such as code generation. Boostrap your scripts with a small script that takes a body of script files without a #! line, and adds one.

The worst possible thing you can do is to start writing entire scripts in such a way that they run on a Bourne shell from 1981. This is only necessary if you must write for a system that doesn't really doesn't have any other shell.