Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pipe stdout to multiple processes [zsh]

Tags:

pipe

zsh

I'm aware of the ability for zsh to do:

ls -1 >foo >bar

But let's say I want to run both outputs through another command. For instance, how would I combine these two commands so as to avoid running mysqldump twice?

mysqldump db1 | bzip2 > db1.sql.bz2
mysqldump db1 | mysql db2

The closest I can come up with is:

mysqldump db1 >db1.sql | mysql db2
bzip2 db1.sql

But I'd rather not write the file to disk uncompressed (it's big!).

like image 824
wuputah Avatar asked Feb 14 '11 17:02

wuputah


1 Answers

The following works:

echo abc > >(gzip > 1) > >(xz > 2)

Modified for your example (but untested):

mysqldump db1 > >(bzip2 > db1.sql.bz2) > >(mysql db2)

or, probably better:

{ mysqldump db1 } > >(bzip2 > db1.sql.bz2) > >(mysql db2)

// I found almost the same example in PROCESS SUBSTITUTION section in man zshexpn:

Also note that the previous example can be more compactly and efficiently written (provided the MULTIOS option is set) as:

   paste <(cut -f1 file1) <(cut -f3 file2) \
   > >(process1) > >(process2)

The shell uses pipes instead of FIFOs to implement the latter two process substitutions in the above example.

There is an additional problem with >(process); when this is attached to an external command, the parent shell does not wait for process to finish and hence an immediately following command cannot rely on the results being complete. The problem and solution are the same as described in the section MULTIOS in zshmisc(1). Hence in a simplified version of the example above:

   paste <(cut -f1 file1) <(cut -f3 file2) > >(process)

(note that no MULTIOS are involved), process will be run asynchronously. The workaround is:

   { paste <(cut -f1 file1) <(cut -f3 file2) } > >(process)

The extra processes here are spawned from the parent shell which will wait for their completion.

like image 135
ZyX Avatar answered Oct 05 '22 07:10

ZyX