Bash – /usr/bin/ls: /usr/bin/ls: cannot execute binary file

bashshell

I'm using git bash on Windows. I want to run ls command with bash. I can run ls separately like this:

$ ls
f1  f2

However, when I try with bash, I get the error:

$ bash ls
/usr/bin/ls: /usr/bin/ls: cannot execute binary file

But if I create my script it works fine:

$ echo "echo \$@" > my.sh && bash my.sh

What can be the problem?

Best Answer

From the fine manual for bash(1):

ARGUMENTS If arguments remain after option processing, and neither the -c nor the -s option has been supplied, the first argument is assumed to be the name of a file containing shell commands.

Does ls contain shell commands? No, it is a binary file. bash squawks about this fact and fails.

A strace may help show what is going on:

$ strace -o alog bash ls
/usr/bin/ls: /usr/bin/ls: cannot execute binary file

The alog file can get a bit messy, but shows bash looking for ls in the current working directory—a security risk if someone has placed a naughty ls file somewhere!—and then does a PATH search:

$ grep ls alog
execve("/usr/bin/bash", ["bash", "ls"], [/* 43 vars */]) = 0
open("ls", O_RDONLY)                    = -1 ENOENT (No such file or directory)
stat("/usr/local/bin/ls", 0x7fff349810f0) = -1 ENOENT (No such file or directory)
stat("/usr/bin/ls", {st_mode=S_IFREG|0755, st_size=117672, ...}) = 0
stat("/usr/bin/ls", {st_mode=S_IFREG|0755, st_size=117672, ...}) = 0
access("/usr/bin/ls", X_OK)             = 0
stat("/usr/bin/ls", {st_mode=S_IFREG|0755, st_size=117672, ...}) = 0
access("/usr/bin/ls", R_OK)             = 0
stat("/usr/bin/ls", {st_mode=S_IFREG|0755, st_size=117672, ...}) = 0
stat("/usr/bin/ls", {st_mode=S_IFREG|0755, st_size=117672, ...}) = 0
access("/usr/bin/ls", X_OK)             = 0
stat("/usr/bin/ls", {st_mode=S_IFREG|0755, st_size=117672, ...}) = 0
access("/usr/bin/ls", R_OK)             = 0
open("/usr/bin/ls", O_RDONLY)           = 3

As to why this could be a security risk, if you run bash somecmd from the wrong directory where someone has created a ls (or some other known command due to a bug in a script):

$ echo "echo rm -rf /" > ls
$ bash ls
rm -rf /
$ 
Related Question