Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unix : run 2 commands which take input from a pipe?

Tags:

unix

pipe

Updated : Thanks for your answers. As I said, my q was just a translation of my usecase. Let me get into more details of what I want to achieve. In my dev env, we use "ade" as our version control system what I want to do is :

ade describetrans | awk '/myapps/{ print $2 }' | sort -fr | xargs -iF ade unbranch F 

Now, every single time I run the unbranch command, a new file/dir gets checked out. so I need to run ade checkin -all after all my unbranch commands. So I needed something like

"pre part till sort" | xargs -iF (ade unbranch + ade checkin -all) 

Any way to run 2 commands on the op of pipe ?

Thanks

Original question asked :

I can translate the usecase I have into the following :

I need to get the 1st line of a file. I do

cat file | head -1 

Now I want to do this on a list of files. How do I do the following in one unix command ?? Eg :

find . -name "*.log" | ( xargs -iF cat F  | head -1 )

Obviously the brackets in the above command do not work.

is there a way to pipe the output of the find command and do 2 commands on it ( cat and head ) ? Tried using ; and && but dint help. I can create a script - but wanted to do this in one command.

Again - this is just a translation of the case I have.

thanks Rohan

like image 563
sms169 Avatar asked Aug 14 '10 20:08

sms169


2 Answers

First of all, head accepts more than one file name, so you can simply write:

 head -q -n 1 *.log

or:

find . -name '*.log' -exec head -n 1 '{}' ';'

However, if you really need to duplicate the stream, then use tee and do something along the lines of:

 wget -O - http://example.com/dvd.iso | tee >(sha1sum > dvd.sha1) > dvd.iso

This example is taken from info coreutils 'tee invocation'.


UPDATE (Following the ade comment) In your case tee will not work. You need to perform a task after another task finishes, and tee will trigger the tasks more or less simultaneously (modulo buffering).

Another approach will work, provided that there are no spaces in the input lines (a serious issue, I know, but I'm not sure how to overcome it right now). I'll start with a generic solution:

echo -e 'Foo\nBar\nBaz' | ( for i in `cat` ; do echo 1$i ; echo 2$i ; done )

Here, echo -e 'Foo\nBar\nBaz' creates a sample multi-line input, echo 1$i is the first command to run, echo 2$i is the second command to run.

I'm not familiar with ade and I don't have it installed on my system, but I'm guessing that in your case something like this might work:

ade describetrans | awk '/myapps/{ print $2 }' | sort -fr | ( for i in `cat` ; do ade unbranch $i ; ade checkin -all $i ; done )
like image 128
Bolo Avatar answered Sep 22 '22 13:09

Bolo


Useless use of cat. Simply pass the file names to head:

find . -name '*.log' -exec head -n 1 '{}' '+'

or

find . -name '*.log' -print0 | xargs -0 head -n 1

EDIT: This will print headers for each file. On Linux, this can be suppressed with -q, but on other systems you must make sure that head is called with a single argument:

find . -name '*.log' -exec head -n 1 '{}' ';'
like image 38
Philipp Avatar answered Sep 26 '22 13:09

Philipp