4

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?

  • 4
    bash -c ls. From the manpage: If the -c option is present, then commands are read from the first non-option argument command_string. If there are arguments after the command_string, they are assigned to the positional parameters, starting with $0. – ridgy Feb 3 '17 at 16:39
  • @ridgy, thanks, it works this way. I'm not very proficient with bash yet. Can you please post an elaborate answer and explain why it works with my custom script without -c option and why it's needed for ls? – Maxim Koretskyi Feb 3 '17 at 16:42
13

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 /
$ 
|improve this answer|||||
  • thanks, can you elaborate a bit on this If arguments remain after option processing? An example maybe? – Maxim Koretskyi Feb 3 '17 at 17:18
  • @Maximus your bash ls is an example of an argument that remains, as bash tried to read it as if it were a file of shell commands. – thrig Feb 3 '17 at 17:20
  • yeah, I understood that. If arguments remain after option processing - what option processing? bash -c -s - these? – Maxim Koretskyi Feb 3 '17 at 17:22
  • @Maximus yes, those are options. Some consume additional arguments. – thrig Feb 3 '17 at 17:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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