Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

Sometimes I see command

find . -name  * -exec ls -a {} \;

I was asked this to execute.

what does {} \; means here?

share|improve this question
1  
-name * is redundant. –  Kevin Aug 29 '13 at 23:35
    
Also check out explainshell for other types of questions like this. Here's the output for your command.. –  Glutanimate Aug 30 '13 at 21:37
4  
-name * is worse than redundant. Because the * is unquoted, the shell expands it to the list of file names in the current folder, with spaces being incorrectly treated, leading to unexpected results or an error message. As an extra point, find has many functions, one of them being to list files; this avoids having to use -exec. E.g., you can use find . -print or find . -ls. Finally, there are two ways to escape the semi-colon: either as you did with the backslash, \;, or by quoting: ';'. Use whichever you feel more comfortable with. –  Paddy Landau Sep 3 '13 at 9:50
add comment

2 Answers 2

up vote 26 down vote accepted

If you run find with exec, {} expands to the filename of each file or directory found with find (so that ls in your example gets every found filename as an argument - note that it calls ls or whatever other command you specify once for each file found).

Semicolon ; ends the command executed by exec. It needs to be escaped with \ so that the shell you run find inside does not treat it as its own special character, but rather passes it to find.

See this article for some more details.


Also, find provides some optimization with exec cmd {} + - when run like that, find appends found files to the end of the command rather than invoking it once per file (so that the command is run only once, if possible).

The difference in behavior (if not in efficiency) is easily noticeable if run with ls, e.g.

find ~ -iname '*.jpg' -exec ls {} \;
# vs
find ~ -iname '*.jpg' -exec ls {} +

Assuming you have some jpg files (with short enough paths), the result is one line per file in first case and standard ls behavior of displaying files in columns for the latter.

share|improve this answer
1  
I think it would be beneficial for you to contrast \; with +. –  Kevin Aug 29 '13 at 23:37
    
How does it differ from find . -name * | ls -a -? –  András Hummer Aug 30 '13 at 11:06
    
@DrH The point is not to let shell do the wildcard expansion but rather pass the wildcard expression to find. Also, output of ls in this case apparently does not depend on the input - no matter what I use as a filter for find, ls just displays the working directory contents and that's all. Check for example find ~ -iname '*.jpg' -exec ls -a {} \; vs find ~ -iname '*.jpg' | ls -a. –  moon.musick Aug 30 '13 at 12:34
    
@DrH or even echo 'foo' | ls -a. –  moon.musick Aug 30 '13 at 12:36
    
@moon.musick, I believe you've missed off the important - in your ls -a - command when testing what @dr-h queried. –  Daniel Llewellyn Sep 6 '13 at 21:42
show 1 more comment

From the manpage for the find command Manpage icon:

-exec command ;
              Execute  command;  true if 0 status is returned.  All following arguments to find are taken to be arguments to
              the command until an argument consisting of `;' is encountered.  The string `{}' is replaced  by  the  current
              file name being processed everywhere it occurs in the arguments to the command, not just in arguments where it
              is alone, as in some versions of find.  Both of these constructions might need to be escaped (with a  `\')  or
              quoted  to  protect them from expansion by the shell.

So here's the explanation:

{} means "the output of find". As in, "whatever find found". find returns the path of the file you're looking for, right? So {} replaces it; it's a placeholder for each file that the find command locates (taken from here).

The \; part is basically telling find "okay, I'm done with the command I wanted to execute".

Example:

Let's say I'm in a directory full of .txt files. I then run:

find . -name  '*.txt' -exec cat {} \;

The first part, find . -name *.txt, returns a list of the .txt files. The second part, -exec cat {} \; will execute the cat command for every file found by find, so cat file1.txt, cat file2.txt, and so on.

share|improve this answer
1  
The part *.txt must be quoted as '*.txt'. This is because if there are .txt files in the current folder, the shell will expand this and you will get incorrect results or an error message. find -name '*.txt' -exec cat {} \; –  Paddy Landau Sep 3 '13 at 9:57
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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