1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
#!/usr/bin/env sh
# Description: Extract and create archives
#
# Supported creation:
# gz, bz2, xz, tar (with gz, bz2, xz), zip, 7z
#
# Supported extraction:
# ar, arj, bz2, cab, chm, cpio, cramfs, deb, dmg, gz, iso, lzh, lzma,
# msi, nsis, qcow2, rpm, squashfs, tar (with gz, bz2, xz), wim, xar,
# xz, zip, Z, 7z
#
# Dependencies:
# - tar, gzip, bzip2, xz
# - 7zip
#
# Usage:
# Extracting archives:
# You can select multiple archives for batch extraction or content preview.
#
# Creating archives:
# Enter a filename with extension (e.g., foo.tar.gz, foo.txz, foo.zip) to
# archive and compress selected files together.
#
# For tar-based formats:
# Files will be archived using relative paths only if all selected files
# are located within the current directory or its subdirectories;
# otherwise, absolute paths will be used.
#
# For zip or 7z formats:
# The directory hierarchy of the selected files will be ignored, and all
# files will be packed directly into the archive without preserving paths.
#
# If you enter just .gz, .bz2, or .xz as the filename, each selected file will
# be individually compressed in the specified format.
#
# Shell: POSIX compliant
#
# Author: Shi Yanling
sffpipe=$1
sffdir=${sffpipe%/*}
tmpdir=${TMPDIR:-/tmp}
[ ! -w "$tmpdir" ] && tmpdir=$sffdir
uid=$(id -u)
tsel="${tmpdir}/sff-tmpsel-$uid"
tbuf1="${tmpdir}/sff-tmpbuf2-$uid"
type 7zz >/dev/null 2>&1 && _7z='7zz' || _7z='7z'
export LC_ALL=C
sffpipe_refresh()
{
[ "$1" = '-c' ] && _x='.' || _x=''
printf "*%s" "$_x" >"$sffpipe"
}
sffpipe_sel_file()
{
printf "@%s\0" "$1" >"$sffpipe"
}
sffpipe_get_sel()
{
printf "%s" "$$" >"$sffpipe"
sel=$sffpipe
}
extract_archive()
{
sffpipe_get_sel
tr '\n\0' '\035\n' <"$sel" >"$tsel"
[ ! -s "$tsel" ] && return 0
printf "\n(l)ist contents / (e)xtract / (c)ancel [c]: "; read -r _x
_selfile=''
while IFS='' read -r _path <&3; do
_path=$(printf "%s" "$_path" | tr '\035' '\n')
_wdir=${_path%/*}
_name=${_path##*/}
_bname=${_name%.?*}
_bname=${_bname%.tar}
case "$_name" in
*?.?*) [ -d "$_path" ] && continue;;
*) continue;;
esac
case "$_x" in
'e') if [ -e "${_wdir}/$_bname" ]; then
printf "\n'%s' exists. Overwrite? (y/n) [n]: " "$_bname"; read -r _x2
[ "$_x2" != 'y' ] && continue
fi
_tdir=$(mktemp -d "${_wdir}/tmp.XXXXXX")
[ -e "${_wdir}/$_bname" ] && rm -rf "${_wdir}/$_bname"
echo "Extracting..."
case "$(printf "%s" "$_name" | tr 'A-Z' 'a-z')" in
*?.tar.?*|*?.t?*) cd "$_tdir" && tar -xvf "$_path";;
*?.gz) gunzip -k "$_path";;
*?.bz2) bunzip2 -k "$_path";;
*?.xz) unxz -k "$_path";;
*?.?*) cd "$_tdir" && "$_7z" x -aoa "$_path";;
esac && _selfile="$_bname" || { printf "Press Enter to continue "; read -r _x2; }
_num=$(find "$_tdir"/ -mindepth 1 -maxdepth 1 ! -name . ! -name .. -print0 | tr '\n\0' '\035\n' | wc -l)
if [ -d "${_tdir}/$_bname" ] && [ "$_num" -eq 1 ]; then
mv "${_tdir}/$_bname" "$_wdir"/
elif [ ! -e "${_wdir}/$_bname" ] && [ "$_num" -gt 0 ]; then
mv "$_tdir" "${_wdir}/$_bname"
fi
[ -e "$_tdir" ] && rm -rf "$_tdir"
;;
'l') unset LC_ALL
echo ""
case "$(printf "%s" "$_name" | tr 'A-Z' 'a-z')" in
*?.tar.?*|*?.t?*) tar -tvf "$_path";;
*?.gz) zcat "$_path";;
*?.bz2) bzcat "$_path";;
*?.xz) xzcat "$_path";;
*?.?*) "$_7z" l "$_path";;
esac
printf "Press Enter to continue "; read -r _x2
;;
*) return 0
;;
esac
done 3<"$tsel"
if [ "$_selfile" ]; then
sffpipe_sel_file "$_selfile"
else
sffpipe_refresh
fi
}
create_archive()
{
sffpipe_get_sel
tr '\n\0' '\035\n' <"$sel" >"$tsel"
[ ! -s "$tsel" ] && return 0
while true; do
printf "\nArchive name (empty to cancel): "; read -r _name
[ -z "$_name" ] && return 0
if [ -e "$_name" ]; then
printf "\n'%s' exists. Overwrite? (y/n) [n]: " "$_name"; read -r _x
[ "$_x" = 'y' ] && break
else
break
fi
done
_pwd=$(printf '%s' "$PWD" | tr '\n' '\035' | sed -e 's/[^^]/[&]/g' -e 's/\^/\\^/g')
if [ "$(sed "/^$_pwd\//d" "$tsel")" ]; then
tr '\n\035' '\0\n' <"$tsel" >"$tbuf1"
else
sed "s|^$_pwd/||" "$tsel" | tr '\n\035' '\0\n' >"$tbuf1"
fi
[ -e "$_name" ] && rm -f "$_name"
case "$(printf "%s" "$_name" | tr 'A-Z' 'a-z')" in
*?.tar.?*|*?.t?*) xargs -0 tar -cavf "$_name" -- <"$tbuf1";;
*.gz) xargs -0 gzip -fk -- <"$tbuf1";;
*.bz2) xargs -0 bzip2 -fk -- <"$tbuf1";;
*.xz) xargs -0 xz -fk -- <"$tbuf1";;
*?.zip|*?.7z) xargs -0 "$_7z" a "$_name" -- <"$tbuf1";;
*) printf "\nUnsupported archive format\n"; false;;
esac
if [ "$?" -eq 0 ]; then
sffpipe_sel_file "$_name"
else
sffpipe_refresh
printf "Press Enter to continue "; read -r _x
fi
}
case "$2" in
'e') extract_archive;;
'c') create_archive;;
esac
rm -f "$tsel" "$tbuf1"
|