Use Python's zipfile library?
~/wrk/tmp$ ls test.zip
ls: cannot access test.zip: No such file or directory
Ok. There is no 'test.zip' right now...
~/wrk/tmp$ python -c 'import zipfile,sys ; zipfile.ZipFile(sys.argv[1],"a").write(sys.a
rgv[2],sys.argv[3])' test.zip /etc/motd text/motd
Let's add '/etc/motd' as 'text/motd' to the nonexisting zipfile...
~/wrk/tmp$ ls -l test.zip
-rw-r--r-- 1 yeti yeti 473 Mar 23 09:51 test.zip
The zipfile library was nice enough to create 'test.zip'.
~/wrk/tmp$ unzip -lv test.zip
Archive: test.zip
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
357 Stored 357 0% 2014-03-20 15:47 ff1b8b7f text/motd
-------- ------- --- -------
357 357 0% 1 file
..and it seems to contain what I wated...
Let's check it by unzipping it to stdout...
~/wrk/tmp$ unzip -p test.zip text/motd
Linux aurora 3.2.0-0.bpo.4-amd64 #1 SMP Debian 3.2.54-2~bpo60+1 x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Fine!
Now we add a 2nd file...
~/wrk/tmp$ python -c 'import zipfile,sys ; zipfile.ZipFile(sys.argv[1],"a").write(sys.argv[2],sys.argv[3])' test.zip /etc/issue otherdir/issue
~/wrk/tmp$ ls -l test.zip
-rw-r--r-- 1 yeti yeti 605 Mar 23 09:52 test.zip
(yeti@aurora:1)~/wrk/tmp$ unzip -lv test.zip
Archive: test.zip
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
357 Stored 357 0% 2014-03-20 15:47 ff1b8b7f text/motd
28 Stored 28 0% 2012-09-21 22:52 f9c3990c otherdir/issue
-------- ------- --- -------
385 385 0% 2 files
~/wrk/tmp$ unzip -p test.zip otherdir/issue Debian GNU/Linux 6.0 \n \l
~/wrk/tmp$ _
I would do something like this (zsh syntax):
unz() (
tmp=$(TMPDIR=. mktemp -d -- ${${argv[-1]:t:r}%.tar}.XXXXXX) || exit
print -r >&2 "Extracting in $tmp"
cd -- $tmp || exit
[[ $argv[-1] = /* ]] || argv[-1]=../$argv[-1]
(set -x; "$@"); ret=$?
files=(*(ND[1,2]))
case $#files in
(0) print -r >&2 "No file created"
rmdir -v "../$tmp";;
(1) mv -v -- $files .. && rmdir -v ../$tmp;;
(*) mv -vT ../$tmp ../$tmp:r;;
esac && exit $ret
)
That is:
- create a directory in anycase
- run the command
- depending on how many files the command generated:
- remove that directory (if it didn't create any file)
- if it created only one file/dir, move it one level up and discard our directory
- otherwise, attempt to strip the random string from the end of our temp directory.
This way, you can do:
unz unzip foo.zip
unz tar xf foo.tar.gz
It assumes that the last argument to the extracting command is the file to extract. It also assumes GNU tools for the -v
options. On non-GNU systems, you can remove those and possibly do the logging by hand. mv -T
is also GNU specific, and is to force mv
to attempt do a rename only.
Best Answer
You can extract just the text to standard output with the
-p
option:This won't extract the metadata (date, permissions, …), only the file contents (obviously, it only works for regular files, not symlinks, devices, directories...). That's the price to pay for the convenience of not having to move the file afterwards.
Alternatively, mount the archive as a directory and just copy the file. With AVFS:
Or with fuse-zip: