31

I want to compress the contents of stdin using zip, for instance:

echo 'foo bar' | zip  > file.zip

This works ok, but when unzipping, the uncompressed file name is -

I was wondering how I could specify a file name for stdin?

Mehdi
  • 803
  • 2
  • 11
  • 16
  • see http://stackoverflow.com/questions/2019603/how-do-you-specify-filenames-within-a-zip-when-creating-it-on-the-command-line-f for an identical problem – valentin Apr 29 '15 at 23:03
  • 4
    It's not identical, there they're working under the presumption they don't know the filename until the data comes in. Maybe Mehdi (well this is my usecase) knows what they want the file to be called when he writes the bash line. Essentially a more efficient version of `echo 'foo bar' > FILENAME && zip file.zip FILENAME && rm FILENAME` – Hashbrown Jun 29 '16 at 02:55

4 Answers4

14

What you can do is pipe the file in normally, then rename it in the zip

echo 'foo bar' | zip  > file.zip
printf "@ -\n@=filename.txt\n" | zipnote -w file.zip
Hashbrown
  • 12,091
  • 8
  • 72
  • 95
  • This is not ideal, as you cannot use this in a stream setup (if the zip itself is being streamed elsewhere) – polvoazul Nov 29 '20 at 15:23
  • I think that's literally impossible, `zip` provides no option to force a name. If you're okay with creating "files" one way might be to pipe your data command into a named pipe instead, then add that named pipe to your streamed zip (which will compress a new file of that name) – Hashbrown Nov 29 '20 at 22:20
7

Use a fifo (a named pipe) instead of piping stdin directly!

mkfifo text.txt               # create fifo
echo 'foo bar' > text.txt &   # pipe data to fifo, in background
zip --fifo file.zip text.txt  # note the `--fifo` argument to zip
rm text.txt                   # cleanup

Result:

$ unzip -l file.zip
Archive:  file.zip
Length      Date    Time    Name
---------  ---------- -----   ----
8          2020-11-29 12:30   text.txt
---------                     -------
8                             1 file

Note that the fifo is a named pipe. Just like the anonymous pipe - the famous | - no data is stored on your hard drive, it is streamed directly from writer to reader.

polvoazul
  • 2,208
  • 2
  • 19
  • 25
  • Questions: How to guarantee that the zip process doesn't stop reading and exit when it has caught up with the data? Does this depend on the swap space and prone to shortages? Is the space reclaimed once the zip process has read a piece of data(I know this is wishful thinking ..)? – gk_2000 Apr 15 '22 at 18:36
  • Its better than you think :) @gk_2000 The pipe just connects whatever process is producing data to the zip process. The pipe will block the zip process for reading if data is not yet available, and block the producing process if zip is not reading data fast enough. There is no space reclaimed because there is no space wasted at all. The producer sends its data directly to zip. When producer exits , it closes the pipe, and the pipe signals to zip that it is "the end of the file" – polvoazul Apr 15 '22 at 23:52
  • In other words, everything "just works" – polvoazul Apr 15 '22 at 23:55
1

Write echo output to the desired filename, then use the -m flag to zip and remove the original file in one step.

echo 'foo bar' > filename.txt && zip -m filename.txt.zip filename.txt

nad7wf
  • 89
  • 1
  • 7
-8

echo 'foo bar' | zip -@ /path/to/zipfile.zip should do it while keeping filename integrity

jwvh
  • 50,871
  • 7
  • 38
  • 64