How to extract files from archives efficiently
Performance of FUSE mounts
Since FUSE file systems can be used with vifm to browse archives and one of the most common task with an archive is extraction of files it contains, it's natural to use copy operation to do that in vifm. Unfortunately there are some issues with performance, which make this significantly slower than it should be. This doesn't seem to be an artifact of FUSE architecture, but rather unoptimized implementation of FUSE mounters. Copying is an I/O intensive operation and vifm sends many requests and because FUSE mounters don't seem to cache even path resolution each request ends up taking a lot of time (relative to time necessary to transfer data itself).
As a workaround this page presents a script, which can be invoked from vifm to extract files from an archive by using 7z and without use of FUSE.
Warning
The script wasn't thoroughly tested, so check that it works correctly before relying on it.
Script
#!/usr/bin/bash
if [ -z "$VIFM_FUSE_FILE" ]; then
echo "error: this command is meant to be run inside vifm FUSE mount"
exit 1
fi
archive="$VIFM_FUSE_FILE"
filename="${archive##*/}"
#Because 7z can't extract these files in one call:
doubleExtraction=0
if [[ $filename =~ ^.*(tar\.gz|tar\.bz2)$ ]] ;
then
doubleExtraction=1
fi
fusehome="$1"
shift
destination="$1"
shift
tempDest=`mktemp -d`
files=
for f; do
# obtain relative path inside archive
f="${f#$fusehome}"
f="${f#/}"
f="${f#*/}"
files=( ${files[@]} "$f" )
done
firstFile=${files[@]:0:1}
IFS='/' read -ra ADDR <<< $firstFile
unset ADDR[${#ADDR[@]}-1]
movePath=$tempDest/
for i in "${ADDR[@]}"; do
movePath=$movePath$i/
done
movePath=$movePath*
if [[ $doubleExtraction = 1 ]]; then
exec 7z x -so "$archive" | 7z x -si -ttar -o$tempDest "${files[@]}" > /dev/null 2>&1 && mv -i $movePath $destination && rm -r $tempDest
else
exec 7z x -o$tempDest "$archive" "${files[@]}" > /dev/null 2>&1 && mv -i $movePath $destination && rm -r $tempDest
fi
vifmrc part
Assuming that the script is called extract-files
and is somewhere in $PATH
, the command to add to vifmrc
is:
command! extractfiles :execute '!%%n extract-files' &fusehome expand('%%D') expand('%%f:p')
How to use
When inside FUSE mounted archive, select files you want to extract into current directory of the inactive pane and run :extractfiles
command.