16

I tried to use the ls command and got an error:

bash: /bin/ls: cannot execute binary file

What can I use instead of this command?

jimmij
  • 47,140

7 Answers7

33

You can use the echo or find commands instead of ls:

echo *

or:

find -printf "%M\t%u\t%g\t%p\n"
psmears
  • 465
  • 3
  • 8
Invoker
  • 1,393
  • 1
  • 16
  • 21
  • 7
    I would use echo -- * – Alex Jones Jun 20 '15 at 05:17
  • what's the difference? It will give you the same output – Invoker Jun 20 '15 at 05:19
  • 9
    @Invoker: If you happen to have a file called -n in the current directory, that would get interpreted as a flag, not something to echo. – MvG Jun 20 '15 at 05:25
  • I don't think you can create file -n [admin ~]$ touch -n touch: invalid option -- 'n' Trytouch --help' for more information.`` – Invoker Jun 20 '15 at 05:30
  • 2
    It would be touch ./-n – Basile Starynkevitch Jun 20 '15 at 05:31
  • ok I did and used my coomand echo *
    [admin ~]$ touch ./-n [admin ~]$ ls Desktop Downloads -n Public test Documents Music Pictures Templates Videos [admin5 ~]$ echo * Desktop Documents Downloads Music -n Pictures Public Templates test Videos and I can see my file -n
    – Invoker Jun 20 '15 at 05:34
  • so what's the difference ? – Invoker Jun 20 '15 at 05:35
  • 1
    @Invoker Alphabetical order matters. Run that oneliner for a case where that makes a difference: rm -rf /tmp/foo && mkdir /tmp/foo && cd /tmp/foo && touch ./-n oops && set -x && ls && echo * – jlliagre Jun 20 '15 at 07:07
  • 3
    echo seems not to honor --, per se.  So how is echo -- * any better than echo "" * or, better yet, echo "The file(s) are:" *? – G-Man Says 'Reinstate Monica' Jun 20 '15 at 08:09
  • @edwardtorvalds: echo takes a single dash for that purpose, not two dashes: echo - *. – Zorawar Jun 20 '15 at 08:47
  • @Zorawar why? other commands like rm we use -- two dashes – Alex Jones Jun 20 '15 at 08:51
  • you should update your command bfr more users use that 'inaccurate' command, sorry i dont mean to be rude but pls dont give 'inaccurate' commands – Alex Jones Jun 20 '15 at 08:53
  • @edwardtorvalds: god knows. It should be two dashes as with most other (GNU) commands so that people aren't caught out. Probably for historical reasons and backwards compatibility if I had to guess... – Zorawar Jun 20 '15 at 08:56
  • @edwardtorvalds: but, I should add, it may not be respected by all versions of echo, whether builtin or external command... – Zorawar Jun 20 '15 at 09:05
  • 1
    @G-Man - well, in the first place, it's apparent that the execution environment is at least a little strange, and that compilation defaults cannot be assumed. And if the version of bash being run has been compiled with *--enable-xpg-echo-default: ...echo ... expand[s] backslash-escaped characters by default ... more like the ... [echo specified in] Single Unix Specification, version 3...* then, well, echo's output is not necessarily a reliable representation of the filenames in question. – mikeserv Jun 21 '15 at 00:34
  • @ EdwardTorvalds: not echo -- *, prefer the good habit of using: echo ./* (some systems will not have the -- option to echo. And even linux probably have programs that don't have '--' as well, so the good habit of using ./ instead works in all those cases and is better.) – Olivier Dulac Jun 21 '15 at 11:14
  • Another workaround: a=(*);echo -n "${a[*]}"$'\n'. – user23013 Jun 21 '15 at 11:55
25

You can also use the printf command, instead of echo:

printf '%s\n' *

printf is superior to echo in this situation in that echo does not respect the "double dash" (--) to signify the end of the argument list (on some systems, including Ubuntu 14.04 which is what I tested it on):

llama@llama:~$ mkdir -p Misc/unix210948
llama@llama:~$ cd !$
cd Misc/unix210948
llama@llama:~/Misc/unix210948$ touch -- -n
llama@llama:~/Misc/unix210948$ ls
-n
llama@llama:~/Misc/unix210948$ echo *
llama@llama:~/Misc/unix210948$ echo -- *
-- -n
llama@llama:~/Misc/unix210948$ printf '%s\n' *
-n

In this case, you cannot achieve the desired result with echo (since a file called -n gets interpreted as an option, and the double dash doesn't work, so you must use printf).

Note that you should always use a format string like the above when dealing with unknown data with printf, since otherwise you could receive unexpected results (thanks to @G-Man for pointing this out in the comments!):

llama@llama:~/Misc/unix210948$ rm ./-n
llama@llama:~/Misc/unix210948$ touch '\n'
llama@llama:~/Misc/unix210948$ ls
\n
llama@llama:~/Misc/unix210948$ printf -- *

llama@llama:~/Misc/unix210948$ printf '%s\n' *
\n

A file called \n is interpreted as a newline by printf. To avoid this, we use a formatting string for printf (%s) and pass it the names of the files (expanded via globbing, as before).

This printf + formatting string solution can handle a wide variety of filenames (and also treats "hidden" files, that is, those starting with a ., the same as ls):

llama@llama:~/Misc/unix210948$ rm ./*
zsh: sure you want to delete all the files in /home/llama/Misc/unix210948/. [yn]? y
llama@llama:~/Misc/unix210948$ touch -- '-n' '\n' 'name with spaces' '.hidden'
llama@llama:~/Misc/unix210948$ ls
-n  \n  name with spaces
llama@llama:~/Misc/unix210948$ printf '%s\n' *
-n
\n
name with spaces

If your printf supports %q, you could also use that (printf '%q\n' *). This will escape spaces, newlines, etc. if there are any strange characters in your filenames. (Thanks to @muru in chat for pointing this out!)

Doorknob
  • 3,093
  • 2
    When dealing with unknown data, you should *ALWAYS* use '%s' (with \n and/or any other constant text you want).  For example, try the commands touch '%.0s' foo bar; ls; printf -- *.  Conversely, I don't see why you need -- when you have a '%s\n' format string. – G-Man Says 'Reinstate Monica' Jun 20 '15 at 07:59
  • @G-Man Good point! Thanks, I overlooked the unnecessary -- with the format string, and I've edited my post to address the other thing. – Doorknob Jun 20 '15 at 08:59
  • The -n filename honestly shouldn't be a problem at all for a POSIX-2001+ echo - on SUSv3 systems the echo utility is required not to accept any options whatsoever. bash's echo and some others do handle the option though, but bash can be compiled with the build option --enable-xpg-echo-default to make it behave correctly all of the time. Correct behavior for echo, though, means always interpreting backlash escapes in its arguments. So any filename with a C-style escape would not be written to output w/ fidelity - echo would translate it. – mikeserv Jun 21 '15 at 08:14
  • 2
    please, please, everyone should stop recommanding '--' when the unix faq since more than 10 years explain that using "./" is better and more portable (works with all programs even the (many) ones that dont handle '--' ) – Olivier Dulac Jun 21 '15 at 11:19
  • 1
    @OliverDulac - not even that would hel[ w/ a conformant echo. – mikeserv Jun 21 '15 at 11:54
8

You should probably use the file and uname utilities to get a better idea of just what the hell is going on with your machine. Your error is indicative of a binary executable compiled for a system architecture incompatible with that on which it is invoked.

On my machine:

uname -m; file /bin/ls

...prints...

x86_64
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=..., stripped

...because all is right with the world there. However, here's a little run of some commands run from my android tablet on an ssh connection to my desktop...

#first copy android ls to desktop
scp /system/bin/ls "$ssh:arm_ls"

ls               100%  151KB 151.4KB/s   00:00

#next login to desktop and run the following
ssh "$ssh" '
   HOME=./arm_ls
   chmod +x ~
   file ~
   bash -c ~ ||
   rm ~
'

./arm_ls: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /system/bin/linker, stripped
bash: ./arm_ls: cannot execute binary file: Exec format error
mikeserv
  • 58,310
  • This is a great answer that covers one scenario and addresses the potential underlying cause. – Pranab Jun 21 '15 at 07:30
  • misread ^^ sorry. why not just copy and use file? why the whole homedir thing? scp to desktop, file on it, and bash ./it ? – Olivier Dulac Jun 21 '15 at 11:24
  • @OlivierDulac -hmm.. i'mnn not sure i get gist of what youre asking exactly. The HOME= thing is so i can just do ~ a bunch of times instead of ./arm_ls - for convenience. The whole point of the exercice is that i cannot use the arm binary on my x86 desktop, and i wanted the output of file to show that it is a very differnt kind of binary than the sydtem's native one - which is shown at top. And so rather than shpw a whole cross-compile, i chose to cpy an incompatible binary i had available to me on my arm dev to my x86 device and show the results and how to ger the bash error. – mikeserv Jun 21 '15 at 11:53
  • 1
    oh, it was just to save a few typing? ok, but I think it makes it more confusing than it should be (it's not codegolf ^^) – Olivier Dulac Jun 21 '15 at 12:08
  • 1
    @OliverDulac - of course it's not code gold, but it's convenient, it's not at all ambiguous, and i hate thumb typing. – mikeserv Jun 21 '15 at 12:10
5

Using bash (or many other shells), you can use tab completion to list files:

$ thisisnotacommand ./public_html/<TAB>
acc/              papers/           android/          l/
sdr/              blast             formalcss.html    switch/
busy/             formalcss.tar.gz  others/           together.jpg
4

If you want something more like ls -l (file size, permissions, owner, timestamps, etc), then stat -- * might be helpful:

$ ls -l
total 8
-rw-rw-r-- 1 ubuntu ubuntu   4 Jun 20 21:50 a.txt
-rw-rw-r-- 1 ubuntu ubuntu 279 Jun 20 21:50 b.txt
$ stat -- *
  File: ‘a.txt’
  Size: 4           Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d  Inode: 787691      Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/  ubuntu)   Gid: ( 1000/  ubuntu)
Access: 2015-06-20 21:50:23.395223851 -0700
Modify: 2015-06-20 21:50:23.395223851 -0700
Change: 2015-06-20 21:50:23.395223851 -0700
 Birth: -
  File: ‘b.txt’
  Size: 279         Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d  Inode: 844130      Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/  ubuntu)   Gid: ( 1000/  ubuntu)
Access: 2015-06-20 21:50:31.763084155 -0700
Modify: 2015-06-20 21:50:51.066758216 -0700
Change: 2015-06-20 21:50:51.066758216 -0700
 Birth: -
$ 

Alternatively if all you wanted to do is misspell ls, then try sl instead. ;-) (go on - try it... you might have to install it)

3

There is very similar utility available on many systems:

dir

According to the info pages it is equivalent to ls -C -b, but it is standalone binary file.

The benefit of using dir (instead of for example shell completion system) is availability of different options like sorting, showing hidden files, colouring etc., just like in the standard ls program.

BTW, I guess its name comes from windows (or rather dos) system.

jimmij
  • 47,140
1

use

 echo -- *
    find . -printf "%M\t%u\t%g\t%p\n"
    ls -C -b