I decided to read a book about Linux/Unix. I've reached a chapter where they try to explain how to pass the output of commands as expansions to the shell.

The following command

file $(ls /usr/bin/* | grep zip)

gives me the error "cannot open "file name (No such file or directory)". On the contrary, when I do

file $(ls | grep zip)

everything appears normally, no matter the folder. Why? Is it some kind of argument restriction?

If I do this

file $(ls Pictures/ | grep jpg)

I get the following:

1234.jpg: ERROR: cannot open 1234.jpg (No such file or directory)

while moving right in the directory that I want to list

nassosdim@ubuntu:~$ cd Pictures/

nassosdim@ubuntu:~/Pictures$ file $(ls | grep jpg)

prints out the result of file

1234.jpg: JPEG image data, JFIF standard 1.01

Can someone explain to me what's going on? :(

  • It would help if you also said what errors you get. Jul 30, 2011 at 20:08
  • Apologies, added.
    – Nassosdim
    Jul 30, 2011 at 20:53
  • Turns out that ls with a directory as an argument results in file names and not the actual paths. Plus as @Caleb pointed out, parsing the output of ls is bad. Thank you for your answers!
    – Nassosdim
    Jul 30, 2011 at 21:41

4 Answers 4


The error is coming because bash is trying to expand the * in your argument to ls using glob pattern matching. It will always through such an error when the glob doesn't match the pattern. The * then gets passed to ls as a real asterisk, which doesn't match a file either so ls will error!

There are several bits about what you are doing that are redundant. I know you are trying to learn a construct, but let's break down some of the bits of what you just accomplished and how it could have been done.

  1. ls /usr/bin is sufficient to list files in the bin directory, you don't need the star at all.
  2. You should never parse the output of ls at all, it is ambiguous and potentially dangerous.
  3. You could get the same effect without grep by doing ls /usr/bin/*zip*, but the ls is still redundant, you can just pass the glob expantion to file: file /usr/bin/*zip*

Lastly, find is usually a better tool for finding files. You could do what you are after like this:

$ find /usr/bin -iname '*zip*' -exec file {} +

The shell expands the * and turns the command into file $(ls /usr/bin/a /usr/bin/b /usr/bin/whatever | grep zip). You don't need to specify a asterisk in UNIX unless you want the shell to expand it to include everything before it passes it to the ls.

i.e. your shell replaces the * with every matching file before it runs the command, which is not how it works on Windows if you're used to that.

Read section 3.4.9 here.

file $(ls /usr/bin/ | grep zip) 

is the right way to do it (right in the sense that you don't need the *, but see Caleb's answer for other issues and options). But note, that actually runs,

file /usr/bin/a /usr/bin/b /usr/bin/whatever


file /usr/bin/a
file /usr/bin/b
file /usr/bin/whatever

again, it doesn't do it the way windows does.


Please try ls /usr/bin/* | grep zip to see what arguments you are feeding to file. I was baffled by the result a bit. On my Ubuntu system, the result is this:


Using ls /usr/bin/* | less we can see why we get that result: after all the files in /usr/bin, ls also lists the contents of the /usr/bin/X11 directory, and it lists them without the directory names prepended.

And when you feed these file names without a directory name to file, file cannot find these files and you get the "No such file or directory" error messages (as a side note: if you get error messages, please don't just say "I got errors", but post the error messages).

Like Caleb already posted, just use file /usr/bin/*zip*.

  • 1
    I apologize about the formatting of my question, this is the first time that I'm posting and realized that I expressed it vaguely so I did the necessary editing.
    – Nassosdim
    Jul 30, 2011 at 20:31
  • @Nassosdim: thank you for making the question clearer (and a screenshot really isn't necessary).
    – elmicha
    Jul 30, 2011 at 20:44

Parsing the results of ls can be a risky business as the output format varies. You'd be better doing something like this:

file /path/to/*.zip

Try a simpler command to demonstrate how process substitution works:

ls $(echo /usr/bin) 

You must log in to answer this question.

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