I have a foo.sh file in my current directory. If I try to run ./foo.sh, I get:

-bash: ./foo.sh: /bin/sh: bad interpreter: Permission denied

But if I run /bin/sh ./foo.sh then it runs fine.

How can I fix this so I can just run ./foo.sh and it automatically runs it with /bin/sh?

Edit: Okay, this is Chrome OS and this particular folder is mounted with noexec. Apparently that foils the ability to just run ./foo.sh; but why? Why can I still run sh foo.sh to achieve the exact same thing? What security, then, does noexec give?

up vote 20 down vote accepted

The noexec flag will appropriately apply to scripts, because that would be the "expected" behavior.

However, setting noexec only stops people who don't know enough about what they're doing. When you run sh foo.sh you're actually running sh from its default location (probably /bin) which is not on a filesystem mounted with noexec.

You can even get around noexec for regular binary files by invoking ld directly.

cp /bin/bash $HOME
/lib/ld-2.7.so $HOME/bash

This will run bash, regardless of whether or not it's on a filesystem mounted with noexec.

  • 5
    +1 for mentioning ld.so (clever) – amphetamachine Feb 3 '11 at 3:59
  • I tried your two commands; "cannot open shared object file: No such file or directory" - due to sh being copied but bash being run. So then I tried /lib/ld-2.10.1.so $HOME/sh and it returned another error while loading shared libraries: /home/chronos/user/sh: failed to map segment from shared object: Operation not permitted. I'm not sure if what you said was untrue, or if something else is interfering. For example, / is mounted as read-only. – Ricket Feb 3 '11 at 4:06
  • Well, I couldn't say for certain because I don't have a copy of ChromeOS to try with. I'm fairly confident that it can work with some modification but without being able to try it myself I don't know what that might be. – bahamat Feb 3 '11 at 15:21
  • Oh well, I'd like to think that it's because Chrome OS is properly locked down. It does seem to be pretty secure but I guess we'll see over time! – Ricket Feb 4 '11 at 4:09
  • I know how ld worked but never made that connection. Thanks for teaching me something today! - though AFAICT this will fail to execute a statically linked binary. – Wyatt8740 Mar 6 '17 at 0:19

You can also get this error (or a very, very similar message) if you try to execute a file with MS-DOS 2-byte (carriage-return linefeed) line endings.

Vim is so smart these days, that it doesn't neccessarily show you the carriage returns as '^M'. So you can get fooled if you don't check what Vim thinks the "file format" is and just rely on the on-screen-appearance.

In this case the "#!/bin/sh^M" causes the kernel to try to find "/bin/sh^M", which it can't. Bad interpreter, indeed.

If you have the option to run the script or program from a USB stick (or other removable media), you can try unmounting and manually re-mounting it:

  1. Plug in USB stick

  2. Find USB stick device with $ mount

  3. Take note of it; let's assume it is /dev/sdb1

  4. Unmount USB stick:

    $ cd /media/removable
    
    $ sudo umount mountpoint
    

Finally, re-mount USB stick:

$ sudo mount /dev/sdb1 mountpoint

With mountpoint the USB stick's mount name

I had the same question. My problem was with the SD card. This worked for me, and it's much simpler than the other answers here. I learned it from Crouton issue #928.

$ sudo mount -o remount,exec /media/removable/SD\ Card

Note that you have to use the mount point, not the device (/dev/mmcblk1p1). Same thing for USB (/dev/sdb1) in your case. Only the mount point is different:

$ sudo mount -o remount,exec /media/removable/USB\ Drive

You'll know it had the desired effect because "noexec" will disappear from the mount options when you query.

For system security reasons on ChromeOS/ChromiumOS certain folders are marked noexec and you either need to remount with the command below, or use an alternate path that doesn't have noexec set, like the second example.

These commands assume you are at least in developer mode and have access to the shell with chronos@localhost / $ and not just crosh> and know the sudo password.

sudo mount -i -o remount,exec /home/chronos/user/

The more sustainable method that should survive an upgrade because Google reserves most of /usr/local for developers:

sudo mkdir -p /usr/local/bin/ && sudo chown -R chronos: /usr/local/bin/
cp ${HOME}/Downloads/foo.sh /usr/local/bin/

The additional benefit of putting things here is that it is in the $PATH already (try echo $PATH to confirm this) so you don't need to use the full path to run scripts or binaries that are in /usr/local/bin and have had chmod +x run on them.

  • 2
    Hi, welcome on the Unix SE! Note, single-command answers aren't considered very HQ here. I suggest to explain, what are you doing and why. – peterh Jul 23 at 14:57

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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