Bash – Writing to Disk and Compressing with xz Simultaneously

bashpipexz

I have a program that writes traces on disk and the size becomes very large. Normally, I use the following commands.

./run output.txt
xz output.txt

Can I pipe xz at the same time as output.txt is being written?

I read How to convert all files from gzip to xz on the fly (and recursively)?, but I am not sure it applies in my case.

Best Answer

If your ./run will produce its output to stdout if not given a file argument (which is customary in Unix/Linux), then you can simply use:

./run | xz -c >output.txt.xz

If it needs a filename argument, but if it's fine writing to a pipe, then you can either use a special device such as /dev/stdout or /dev/fd/1 (both should be equivalent), like so:

./run /dev/stdout | xz -c >output.txt.xz

Or you can use process substitution, which is typically available in most modern shells such as bash, zsh, or ksh, which will end up using a device from /dev/fd behind the scenes to accomplish the same:

./run >(xz -c >output.txt.xz)

This last one also needs ./run to be able to write to a pipe, but it should work better than the others if ./run writes to output.txt and to stdout in its normal operation, in which case the output would get mixed up if you redirect both to stdout.

Programs are usually ok writing to a pipe, but some of them might want to seek and rewind to offsets within an output file, which is not possible in a pipe. If that's the case, then writing to a temporary file and then compressing it is probably all you can do.