Does your version of tar
not support the switch -z
?
$ tar ztvf file.tar.gz | grep fliename
This would then return the name of the file if it existed at all in the archive.
Extracting the file
You could do something like this if you wanted to search for the file first, and only if present then extract it.
$ arc="<tarball>"; file="<file to extract>"; \
tar ztvf $arc | grep $file && tar zxvf $arc $file
Sample Tarball
$ tar ztvf ffmpeg.static.64bit.2013-10-05.tar.gz
-rwxr-xr-x root/root 19579304 2013-10-05 00:06 ffmpeg
-rwxr-xr-x root/root 19528712 2013-10-05 00:06 ffprobe
Example
$ arc="ffmpeg.static.64bit.2013-10-05.tar.gz"; file="ffmpeg"; \
tar ztvf $arc | grep $file && tar zxvf $arc $file
-rwxr-xr-x root/root 19579304 2013-10-05 00:06 ffmpeg
ffmpeg
Confirmation
$ ll ffmpeg
-rwxr-xr-x 1 manny manny 19579304 Oct 5 00:06 ffmpeg*
A different directory
If you want to output the extracted file to some other location you can use tar
's -C
switch.
$ arc="<tarball>"; file="<file to extract>"; \
tar ztvf $arc | grep $file && tar zxvf $arc -C /path/to/dir $file
Example #1
$ arc="ffmpeg.static.64bit.2013-10-05.tar.gz"; \
file="ffmpeg"; tar ztvf $arc | grep $file && tar zxvf $arc -C /tmp $file
Confirmation
$ ll /tmp/ffmpeg
-rwxr-xr-x 1 manny manny 19579304 Oct 5 00:06 /tmp/ffmpeg*
Example #2
$ arc=cp210x.tar.gz; file="cp210x/usb-serial/Makefile"; \
tar ztvf $arc | grep $file && tar zxvf $arc -C /tmp $file
Confirmation
$ ll /tmp/cp210x/usb-serial/Makefile
-rw-rw-r-- 1 manny manny 388 May 13 01:37 /tmp/cp210x/usb-serial/Makefile
Example #3
Wildcards could also be used if you want to extract a pattern of files.
$ arc=cp210x.tar.gz; file='*Makefile'; \
tar ztvf $arc | grep -E "$file" && tar zxvf $arc -C /tmp --wildcards "$file"
Confirmation
$ find /tmp/cp210x -ls | grep Makefile
26881948 4 -r--r--r-- 1 manny manny 171 Mar 14 2012 /tmp/cp210x/Linux_3.x.x_VCP_Driver_Source/Makefile
26881960 4 -rw-rw-r-- 1 manny manny 388 May 13 01:37 /tmp/cp210x/usb-serial/Makefile
Details
The above involves a couple of additional changes. We're extracting everything that matches '*Makefile'
. Notice that we've wrapped it in single quotes vs. double quotes now. This is to protect the *Makefile
from getting accidentally expanded.
grep
now includes the switch -E
, because we're searching for a regular expression now and not just a single string within the output of tar
. Also the argument to grep
is also not wrapped in double quotes.
We now use the switch --wildcards
to the 2nd tar
so that we can extract based on a pattern rather than just a single file. This argument too is now wrapped in double quotes to protect it.
You could mount the archive with archivemount or mountavfs and recreate it again
archivemount tarfile.tar /mnt
cd /mnt
tar cf /tmp/tarfile.tar --transform 's/foo/bar/' .
write operations on the archive filesystem will perfom a full rewrite on umount, so don't seem a good option for large files.
EDIT
I don't know implementation details but seem like we are saving the write files to filesystem step.
Just test to solve dudes, (over a tar of my /usr)
#!/bin/bash
# try to avoid slab cache issues
cat /tmp/usr.tar > /dev/null
T="$(date +%s)"
tar xf /tmp/usr.tar
tar cf usr.tar usr --transform 's/usr/foo/'
T="$(($(date +%s)-T))"
echo "Tar/Untar seconds: ${T}"
T="$(date +%s)"
archivemount -o readonly -o nobackup /tmp/usr.tar /mnt
tar cf usr.tar /mnt --transform 's/usr/foo/'
umount /mnt
T="$(($(date +%s)-T))"
echo "Archivemount seconds: ${T}"
T="$(date +%s)"
mountavfs
cd '/root/.avfs/tmp/usr.tar#'
tar cf /tmp/test/usr.tar --transform 's/usr/foo/' .
T="$(($(date +%s)-T))"
echo "Avfs seconds: ${T}"
Output:
Tar/Untar seconds: 480
Archivemount seconds: failure, a lot of read errors.
Avfs seconds: 217
So Avfs wins!.
Best Answer
It's probably a GNU specific option, but you could use the
-O
or--to-stdout
to extract files to standard output