The manpage for zip
says (at least on my system):
If a file list is specified as -@ [Not on MacOS], zip takes the list of input files from standard input instead of from the command line. For example,
zip -@ foo
will store the files listed one per line on stdin in foo.zip.
The manpage for tar
-O, --to-stdout
extract files to standard output.
So, in short:
tar -O
can output the files (but not their names) in one long stream to stdout
. But zip
expects a list of filenames on stdin
. So that's not going to work. And it's hard to see how to make it work, because bash pipes are just unstructured strings, but to transmit the information from tar to zip you need to add some structure, even if it is minimal:
[filename][filedata][filename][filedata]...
And the sender (tar
) and receiver (zip
) would have to agree on the format of that structure. Which is not going to happen.
However, you can use interfaces to tar
and zip
other than the command-line utilities. For example, if you have python installed, the following should work:
#!/usr/bin/python
import sys
import tarfile
import zipfile
tarf = tarfile.open(sys.argv[1], "r:*")
zipf = zipfile.ZipFile(sys.argv[2], "w", zipfile.ZIP_DEFLATED)
for m in tarf:
if m.isreg():
zipf.writestr(m.path, tarf.extractfile(m).read())
(Needs lots of error checking. As written, it just crashes on any error.)
You can make that into a shell "one-very-long-liner" although personally I'd just use the python script above.
python -c "$(printf %s \
'import sys;import tarfile;import zipfile;' \
'T=tarfile.open(sys.argv[1],"r:*")' \
'Z=zipfile.ZipFile(sys.argv[2],"w",zipfile.ZIP_DEFLATED);' \
'[Z.writestr(m.path,T.extractfile(m).read()) for m in T if m.isreg()]')" \
input.tar output.zip
(If you want to pipe from curl into that, use /dev/stdin
as the input file. I think that will avoid Python trying to interpret stdin
as a UTF-8 stream.)