Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm trying to run multiple commands on things I have found, how can I achieve this?

find . -exec cmd1; cmd2

does not seem to work; it instead runs cmd2 after cmd1 has been executed on every file.

share|improve this question
up vote 28 down vote accepted

In this demonstration, I'll use sh -c 'echo first; false' (or true) for the first -exec. That will give some output and also have the selected exit code effect. Then echo second will be used for the second one. Assume that there's one file in the current directory.

$ find . -type f -exec sh -c 'echo first; false' \; -exec echo second \;
$ find . -type f -exec sh -c 'echo first; true' \; -exec echo second \;
$ find . -type f \( -exec sh -c 'echo first; false' \; -false -o -exec echo second \; \)
$ find . -type f \( -exec sh -c 'echo first; false' \; -false -o -exec echo second \; \)

A real command of this type would look like:

find . -type f \( -exec command1 \; -false -o -exec command2 \; \)

In the second set, the escaped parentheses group the two -exec clauses. The -false between them forces the test state to "false" and the -o causes the next expression (the second -exec) to be evaluated because of the -false.

From man find:

expr1 expr2
Two expressions in a row are taken to be joined with an implied "and"; expr2 is not evaluated if expr1 is false.

expr1 -a expr2
Same as expr1 expr2.

expr1 -o expr2
Or; expr2 is not evaluated if expr1 is true.

share|improve this answer
Ah yes, I forgot about -o. – Ignacio Vazquez-Abrams Jan 22 '11 at 22:26

If you don't matter about cmd1 being able to prevent cmd2 from being run due to the error code 0:

find . -exec cmd1 \; -exec cmd2 \;

The only reliable way to get both commands to always run this is to have find invoke a shell that will subsequently run the commands in sequence:

find . -exec bash -c 'cmd1; cmd2' filedumper {} \;
share|improve this answer

If you don't mind making a script that does cmd1 and cmd2, then it's just this:

find . -exec myscript {} \;


find . -exec myscript {} +

Use \; or + depending on whether myscript can handle more than one file at a time (gets hairy if there's spaces in filenames, etc).

Putting what you were doing in a script, in my experience, has almost always been worth it. If you have to do it once, you'll have to do it again.

But a neat trick is to put the find inside the script:

if [ $# -gt 0 ]; then
    for each; do
        touch $each
    find . -exec $0 {} +

Then myscript works on whatever files you give as arguments for it to work on, but if you don't give it any arguments, it runs find from the current dir, and then calls itself on the found files. This gets around the fact that find -exec can't call shell functions you've defined in your script.

share|improve this answer

I have been trying both previous solutions without much luck. This one has worked nicely for me:

$ for i in `find . -exec echo {} \;`; do cmd1 $i; cmd2 $i; done
share|improve this answer

try command:

sudo find -name "*[!0-9][1-9].txt" -exec chmod 744 * {} \; -a -exec ls -l {} \; | sort | parallel ls -l
share|improve this answer
Eh, that's not a good idea. The * in the -exec part will expand to all files in the current directory. Especially when running as sudo. – slhck Nov 24 '13 at 8:43

You must log in to answer this question.

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