8

I'd like to be able to run multiple commands on the same file in a single line. The way I currently do this is:

commandA file && commandB file && perl -ne '...' file

My gut instinct tells me that there should be a way to provide the filename argument only once and pipe it to both commands simultaneously through xargs or something similar:

find file | xargs commandA && xargs commandB && xargs perl -ne '...'

When I try this, only the first command runs. How can I achieve what I want to do?

12

You can define a local variable for this:

f=file; commandA $f && commandB $f && ...

You can also execute all unconditionally (replacing && with ;) or in parallel (replacing && with &).

Alternatively, you can also use shell history expansion to reference previous arguments:

commandA file && commandB !:1 && ...
  • Not quite what I had in mind, but is an interesting alternative. – Zaid Aug 30 '10 at 9:50
  • What is wrong with this answer? – Chris Aug 30 '10 at 17:48
  • This is really cool! Is there a way not defining a new variable? – user Feb 4 '16 at 3:20
  • @user, I've added an alternative. – maxschlepzig Feb 4 '16 at 7:39
8

For shells such as Bash, Korn and Z that have process substitution, you can do this:

find file | tee >(xargs commandA) >(xargs commandB) >(xargs perl -ne '...')
2

You can use xargs to construct a command line e.g.:

echo file | xargs -i -- echo ls -l {}\; wc -l {}

Just pipe the above into bash to run it:

echo file | xargs -i -- echo ls -l {}\; wc -l {} | bash

Extending the example to all the *.c files in the current directory (escaping the ls here to prevent any shell alias substitution):

\ls -1 *.c | xargs -i -- echo ls -l {}\; wc -l {} | bash
  • Used this to get a listing of all of files contained in directories where the name is like "enums": find . -name "*enums*" | xargs -i echo -e echo {}\; ls -lh {}\; echo -e '\n\n' | bash – Matt Lachman Jun 2 '11 at 18:34
1

I wouldn't vote for this myself. It's silly and dangerous, but just in the interest of listing the ways to do this, there's:

for cmd in "commandA" "commandB" "perl -ne '...'" ; do eval $cmd file ; done

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.