6

I have a script that use shebang : #!/bin/sh, but when I run it in my Ubuntu 14.04 terminal, it doesn't work and it says that some lines has unexpected operator.

My friend in MacOSX could run that script using the #!/bin/sh shebang.

I tried to change the shebang into #!/usr/bin/env bash, and suddenly, the script works! What happen here actually?

I really hope that I could also run the !#/bin/sh shebang, so that I don't need to change each script that I have.

1
  • 6
    I recommend you edit this to tell us [a] the complete and exact text of the error message, [b] what operating system your friend's computer is running (is it also Ubuntu? or is it Fedora or some other OS?), [c] if possible, can you show us the script? This would facilitate a definitive answer. Also: did you write this script? Is your goal to make it work on both your and your friend's computer, with #!/bin/sh as the hashbang line? With more information this can be definitively answered; until then, I believe muru's answer is the best that can be given. Oct 16, 2014 at 7:16

2 Answers 2

25

Your friend on another computer probably uses an OS which has /bin/sh linked to /bin/bash. In Ubuntu (actually, Debian and most Debian derivatives), /bin/sh is not linked to /bin/bash, but to /bin/dash, which doesn't support many bash-specific features, but is considerably faster.

On Arch Linux:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Sep 28 15:26 /bin/sh -> bash

On Ubuntu:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Feb 19  2014 /bin/sh -> dash

The right thing to do

If you use a shebang, mean it. Since your script contains bash-isms, use /bin/bash in the shebang. Or write portable, POSIX-compliant code.

You can speed up this process by using the checkbashisms program mentioned in this LWN article. It's part of the devscripts package, so install it first:

sudo apt-get install devscripts

Thus:

checkbashisms /path/to/script.sh || sed -i '1 s;/bin/sh;/bin/bash;' /path/to/script.sh

You can convert this to a script (say convert.sh):

#! /bin/sh

for i
do
    checkbashisms "$i"
    if [ $? = "1" ]
    then
        sed -i '1 s;/bin/sh;/bin/bash;' "$i"
    fi
done

The specific return code of 1 means that checkbashisms found a possible bashism, and other return values indicate other problems (file not readable, missing shebang, etc.), so we can check for that particular return value.

And then call it with:

./convert.sh /path/to/first/script.sh /path/to/second/script.sh
# or 
./convert.sh *.sh
# or
find . -iname '*.sh' -exec ./convert.sh {} +

The wrong thing to do

Replace /bin/sh with a symbolic link to /bin/bash.

Recommended reading:

7
  • I use Ubuntu 14.04 and as you said, when I run ls -l /bin/sh it shows that my /bin/sh -> dash So, is there no other solution for me if I don't want to update the script one by one? Oct 16, 2014 at 7:18
  • The "wrong thing to do" is one solution, and another is to replace calls to the script with bash /path/to/script.
    – muru
    Oct 16, 2014 at 7:19
  • 1
    you can simply wright a small script to change the shebang(s) :) Oct 16, 2014 at 7:20
  • 1
    @blinker check the updated answer.
    – muru
    Oct 16, 2014 at 7:30
  • 1
    @blinker that depends on the script. But usually, no. If the script ran correctly for you with bash, it should run correctly for others with bash.
    – muru
    Oct 16, 2014 at 7:53
0

In my case the problem was the export of IFS variable definition in ~/.bashrc (~/.profile)

#Loop over filenames with spaces
export IFS=$'\n'

When changed to either
export IFS=$' \t\n' #default according to man dash
or
IFS=$'\n'
#!/bin/sh scripts started working again. In the latter case the definition no longer propagates to forked /bin/sh processes. The meaning of IFS is explained here and setting it to '\n' causes problems in scripts interpreted by dash shell, which may be the default shell /bin/sh -> dash linked to in your distribution (e.g. debian).

You must log in to answer this question.

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