464 lines
17 KiB
Bash
Executable File
464 lines
17 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# install_keyboard_shortcut=<Control>E
|
|
|
|
# Source the script 'common-functions.sh'.
|
|
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
|
|
ROOT_DIR=$(grep --only-matching "^.*scripts[^/]*" <<<"$SCRIPT_DIR")
|
|
source "$ROOT_DIR/common-functions.sh"
|
|
|
|
_main() {
|
|
local input_files=""
|
|
local output_dir=""
|
|
|
|
# Execute initial checks.
|
|
_check_dependencies ""
|
|
input_files=$(_get_files "par_type=file")
|
|
|
|
local dependencies=""
|
|
dependencies=$(_get_dependencies "$input_files")
|
|
_check_dependencies "$dependencies"
|
|
_display_wait_box "0"
|
|
|
|
export -f \
|
|
_all_commands_exists \
|
|
_get_command \
|
|
_run_command
|
|
|
|
# Execute the function '_main_task' for each file in parallel.
|
|
_run_task_parallel "$input_files" "$output_dir"
|
|
_display_result_box ""
|
|
}
|
|
|
|
_main_task() {
|
|
local input_file=$1
|
|
local output_dir=$2
|
|
|
|
# Run the main process.
|
|
local command=""
|
|
command=$(_get_command "$input_file" "available")
|
|
_run_command "$input_file" "$command" "$output_dir"
|
|
}
|
|
|
|
_get_dependencies() {
|
|
local input_files=$1
|
|
local dependencies=""
|
|
|
|
# Check dependencies for each file.
|
|
for input_file in $input_files; do
|
|
local command=""
|
|
command=$(_get_command "$input_file" "available")
|
|
|
|
# If there is an available command, skip the dependency.
|
|
if [[ -n "$command" ]]; then
|
|
continue
|
|
fi
|
|
|
|
command=$(_get_command "$input_file" "default")
|
|
|
|
case $command in
|
|
"7za")
|
|
dependencies+="
|
|
command=7za; pkg_manager=apt; package=p7zip-full |
|
|
command=7za; pkg_manager=dnf; package=p7zip |
|
|
command=7za; pkg_manager=pacman; package=p7zip |
|
|
command=7za; pkg_manager=zypper; package=p7zip"
|
|
;;
|
|
"ar") dependencies+="command=ar; package=binutils" ;;
|
|
"bsdtar")
|
|
dependencies+="
|
|
command=bsdtar; pkg_manager=apt; package=libarchive-tools |
|
|
command=bsdtar; pkg_manager=dnf |
|
|
command=bsdtar; pkg_manager=pacman; package=libarchive |
|
|
command=bsdtar; pkg_manager=zypper"
|
|
;;
|
|
"bsdtar+unar+7za")
|
|
dependencies+="
|
|
command=bsdtar; pkg_manager=apt; package=libarchive-tools |
|
|
command=bsdtar; pkg_manager=dnf |
|
|
command=bsdtar; pkg_manager=pacman; package=libarchive |
|
|
command=bsdtar; pkg_manager=zypper"
|
|
dependencies+=$'\n'
|
|
dependencies+="
|
|
command=unar; pkg_manager=apt |
|
|
command=unar; pkg_manager=dnf |
|
|
command=unar; pkg_manager=pacman; package=unarchiver |
|
|
command=unar; pkg_manager=zypper"
|
|
dependencies+=$'\n'
|
|
dependencies+="
|
|
command=7za; pkg_manager=apt; package=p7zip-full |
|
|
command=7za; pkg_manager=dnf; package=p7zip |
|
|
command=7za; pkg_manager=pacman; package=p7zip |
|
|
command=7za; pkg_manager=zypper; package=p7zip"
|
|
;;
|
|
"bzip2") dependencies+="command=bzip2" ;;
|
|
"cpio") dependencies+="command=cpio" ;;
|
|
"gpg")
|
|
dependencies+="
|
|
command=gpg; pkg_manager=apt; package=gpg |
|
|
command=gpg; pkg_manager=dnf; package=gnupg2 |
|
|
command=gpg; pkg_manager=pacman; package=gnupg |
|
|
command=gpg; pkg_manager=zypper; package=gpg2"
|
|
;;
|
|
"gzip") dependencies+="command=gzip" ;;
|
|
"lha") dependencies+="command=lha; package=lhasa" ;;
|
|
"lrzip") dependencies+="command=lrzip" ;;
|
|
"lz4") dependencies+="command=lz4" ;;
|
|
"lzip") dependencies+="command=lzip" ;;
|
|
"lzop") dependencies+="command=lzop" ;;
|
|
"tar") dependencies+="command=tar" ;;
|
|
"tar+bzip2") dependencies+="command=tar | command=bzip2" ;;
|
|
"tar+gzip") dependencies+="command=tar | command=gzip" ;;
|
|
"tar+lrzip") dependencies+="command=lrztar; package=lrzip" ;;
|
|
"tar+lz4") dependencies+="command=tar | command=lz4" ;;
|
|
"tar+lzip") dependencies+="command=tar | command=lzip" ;;
|
|
"tar+lzop") dependencies+="command=tar | command=lzop" ;;
|
|
"tar+xz")
|
|
dependencies+="
|
|
command=tar |
|
|
command=xz; pkg_manager=apt; package=xz-utils |
|
|
command=xz; pkg_manager=dnf |
|
|
command=xz; pkg_manager=pacman |
|
|
command=xz; pkg_manager=zypper"
|
|
;;
|
|
"tar+zstd") dependencies+="command=tar | command=zstd" ;;
|
|
"unar")
|
|
dependencies+="
|
|
command=unar; pkg_manager=apt |
|
|
command=unar; pkg_manager=dnf |
|
|
command=unar; pkg_manager=pacman; package=unarchiver |
|
|
command=unar; pkg_manager=zypper"
|
|
;;
|
|
"unrar") dependencies+="command=unrar" ;;
|
|
"unsquashfs")
|
|
dependencies+="
|
|
command=unsquashfs; pkg_manager=apt; package=squashfs-tools |
|
|
command=unsquashfs; pkg_manager=dnf; package=squashfs-tools |
|
|
command=unsquashfs; pkg_manager=pacman; package=squashfs-tools |
|
|
command=unsquashfs; pkg_manager=zypper; package=squashfs"
|
|
;;
|
|
"unzip") dependencies+="command=unzip" ;;
|
|
"xorriso") dependencies+="command=xorriso" ;;
|
|
"xz")
|
|
dependencies+="
|
|
command=xz; pkg_manager=apt; package=xz-utils |
|
|
command=xz; pkg_manager=dnf |
|
|
command=xz; pkg_manager=pacman |
|
|
command=xz; pkg_manager=zypper"
|
|
;;
|
|
"zpaq") dependencies+="command=zpaq" ;;
|
|
"zstd") dependencies+="command=zstd" ;;
|
|
esac
|
|
dependencies+=$'\n'
|
|
done
|
|
|
|
printf "%s" "$dependencies"
|
|
}
|
|
|
|
_get_command() {
|
|
local input_file=$1
|
|
local command_status=$2
|
|
local preferred_commands=""
|
|
local command=""
|
|
|
|
# Define the preferred commands for each archive format.
|
|
case "${input_file,,}" in
|
|
*.tar.bz | *.tbz | *.tar.bz2 | *.tbz2 | *.tb2) preferred_commands="tar+bzip2 unar 7za" ;;
|
|
*.tar.gz | *.tgz) preferred_commands="tar+gzip unar 7za" ;;
|
|
*.tar.lrz | *.tlrz) preferred_commands="tar+lrzip" ;;
|
|
*.tar.lz) preferred_commands="tar+lzip" ;;
|
|
*.tar.lz4) preferred_commands="tar+lz4" ;;
|
|
*.tar.lzma | *.tlz) preferred_commands="tar+lzma unar 7za" ;;
|
|
*.tar.lzo | *.tzo) preferred_commands="tar+lzop" ;;
|
|
*.tar.xz | *.txz) preferred_commands="tar+xz unar 7za" ;;
|
|
*.tar.z | *.taz) preferred_commands="tar+gzip unar 7za" ;;
|
|
*.tar.zst | *.tzst) preferred_commands="tar+zstd" ;;
|
|
*.7z) preferred_commands="7za unar bsdtar" ;;
|
|
*.ace) preferred_commands="unar" ;;
|
|
*.alz) preferred_commands="unar" ;;
|
|
*.ar) preferred_commands="ar bsdtar" ;;
|
|
*.arc) preferred_commands="unar" ;;
|
|
*.arj) preferred_commands="unar" ;;
|
|
*.bz | *.bz2) preferred_commands="bzip2 unar 7za" ;;
|
|
*.cab) preferred_commands="unar" ;;
|
|
*.cpio) preferred_commands="cpio unar bsdtar" ;;
|
|
*.deb | *.udeb) preferred_commands="ar" ;;
|
|
*.gpg | *.asc | *.pgp) preferred_commands="gpg" ;;
|
|
*.gz) preferred_commands="gzip unar 7za" ;;
|
|
*.iso) preferred_commands="xorriso bsdtar" ;;
|
|
*.lrz) preferred_commands="lrzip" ;;
|
|
*.lz) preferred_commands="lzip" ;;
|
|
*.lz4) preferred_commands="lz4" ;;
|
|
*.lzh | *.lzs | *.lha) preferred_commands="lha unar" ;;
|
|
*.lzma) preferred_commands="xz unar" ;;
|
|
*.lzo) preferred_commands="lzop" ;;
|
|
*.msi) preferred_commands="unar" ;;
|
|
*.pak) preferred_commands="unar" ;;
|
|
*.rar) preferred_commands="unrar unar bsdtar" ;;
|
|
*.sit) preferred_commands="unar" ;;
|
|
*.sqsh | *.squashfs | *.sfs) preferred_commands="unsquashfs" ;;
|
|
*.tar | *.gtar | *.gem) preferred_commands="tar bsdtar unar 7za" ;;
|
|
*.xar) preferred_commands="unar bsdtar" ;;
|
|
*.xz) preferred_commands="xz unar 7za" ;;
|
|
*.z) preferred_commands="gzip unar" ;;
|
|
*.zip) preferred_commands="7za bsdtar unar unzip" ;;
|
|
*.zoo) preferred_commands="unar" ;;
|
|
*.zpaq) preferred_commands="zpaq" ;;
|
|
*.zst) preferred_commands="zstd" ;;
|
|
*) preferred_commands="bsdtar+unar+7za" ;;
|
|
esac
|
|
|
|
local preferred_commands_array=()
|
|
IFS=" " read -r -a preferred_commands_array <<<"$preferred_commands"
|
|
|
|
if [[ "$command_status" == "default" ]]; then
|
|
# The default command is the first command of preferred commands.
|
|
command=${preferred_commands_array[0]}
|
|
elif [[ "$command_status" == "available" ]]; then
|
|
# Get the available command in the system.
|
|
local preferred_command=""
|
|
for preferred_command in "${preferred_commands_array[@]}"; do
|
|
if [[ "$preferred_command" == *"+"* ]]; then
|
|
if _all_commands_exists "${preferred_command//+/ }"; then
|
|
command=$preferred_command
|
|
break
|
|
fi
|
|
elif _command_exists "$preferred_command"; then
|
|
command=$preferred_command
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
printf "%s" "$command"
|
|
}
|
|
|
|
_run_command() {
|
|
local input_file=$1
|
|
local command=$2
|
|
local output_dir=$3
|
|
local exit_code=0
|
|
local filename=""
|
|
local std_output=""
|
|
|
|
if [[ -z "$output_dir" ]]; then
|
|
output_dir=$(dirname -- "$input_file")
|
|
fi
|
|
|
|
# Try to use the command '7z' instead of '7za'.
|
|
local command_7za="7za"
|
|
if [[ "$command" == *"7za"* ]]; then
|
|
_command_exists "7z" && command_7za="7z"
|
|
fi
|
|
|
|
filename=$(basename -- "$input_file") # Remove the path.
|
|
filename=$(_strip_filename_extension "$filename") # Remove the extension.
|
|
|
|
__temp_dir_cd() {
|
|
temp_dir_output=$(_get_temp_dir_local "$output_dir" "$filename")
|
|
pushd "$temp_dir_output" &>/dev/null || true
|
|
}
|
|
__temp_dir_exit() {
|
|
# Exit the temporary directory.
|
|
popd &>/dev/null || true
|
|
}
|
|
__temp_dir_remove() {
|
|
rm -rf -- "$temp_dir_output" &>/dev/null
|
|
}
|
|
__get_password() {
|
|
_display_password_box "Enter the password for the archive '$(basename -- "$input_file")'.\nPassword:"
|
|
}
|
|
|
|
# Use a local temporary directory to work.
|
|
__temp_dir_cd
|
|
|
|
case "$command" in
|
|
"7za")
|
|
std_output=$($command_7za x -aoa -p"null" -- "$input_file" 2>&1)
|
|
exit_code=$?
|
|
|
|
if ((exit_code != 0)) && grep -i -q "wrong password" <<<"$std_output"; then
|
|
local password=""
|
|
__temp_dir_exit && __temp_dir_remove
|
|
password=$(__get_password) || exit 1
|
|
__temp_dir_cd
|
|
std_output=$($command_7za x -aoa -p"$password" -- "$input_file" 2>&1)
|
|
exit_code=$?
|
|
fi
|
|
;;
|
|
"ar") std_output=$(ar x -- "$input_file" 2>&1) ;;
|
|
"bsdtar")
|
|
std_output=$(bsdtar --passphrase "null" -xf "$input_file" 2>&1)
|
|
exit_code=$?
|
|
|
|
if ((exit_code != 0)) && grep -i -q "incorrect passphrase" <<<"$std_output"; then
|
|
local password=""
|
|
__temp_dir_exit && __temp_dir_remove
|
|
password=$(__get_password) || exit 1
|
|
__temp_dir_cd
|
|
std_output=$(bsdtar --passphrase "$password" -xf "$input_file" 2>&1)
|
|
exit_code=$?
|
|
fi
|
|
;;
|
|
"bzip2") std_output=$(bzip2 -d -c -k -- "$input_file" >"$filename") ;;
|
|
"cpio") std_output=$(cpio -idv <"$input_file" 2>&1) ;;
|
|
"gpg") std_output=$(gpg --batch --yes --decrypt --output "$filename" -- "$input_file" 2>&1) ;;
|
|
"gzip") std_output=$(gzip -d -c -k -- "$input_file" >"$filename") ;;
|
|
"lha") std_output=$(lha -e "$input_file" 2>&1) ;;
|
|
"lrzip") std_output=$(lrzip -d -o "$temp_dir_output/$filename" -- "$input_file" 2>&1) ;;
|
|
"lz4") std_output=$(lz4 -d -c -- "$input_file" >"$filename") ;;
|
|
"lzip") std_output=$(lzip -d -c -k -- "$input_file" >"$filename") ;;
|
|
"lzop") std_output=$(lzop -d -- "$input_file" 2>&1) ;;
|
|
"tar+bzip2") std_output=$(tar --extract --bzip2 --file="$input_file" 2>&1) ;;
|
|
"tar+gzip") std_output=$(tar --extract --gzip --file="$input_file" 2>&1) ;;
|
|
"tar+lrzip") std_output=$(lrztar -d "$input_file" 2>&1) ;;
|
|
"tar+lzip") std_output=$(tar --extract --lzip --file="$input_file" 2>&1) ;;
|
|
"tar+lz4") std_output=$(lz4 -d -c -- "$input_file" | tar xf -) ;;
|
|
"tar+lzma") std_output=$(tar --extract --lzma --file="$input_file" 2>&1) ;;
|
|
"tar+lzop") std_output=$(tar --extract --lzop --file="$input_file" 2>&1) ;;
|
|
"tar+xz") std_output=$(tar --extract --xz --file="$input_file" 2>&1) ;;
|
|
"tar+z") std_output=$(tar --extract --file="$input_file" 2>&1) ;;
|
|
"tar+zstd") std_output=$(zstd -f -d -c -- "$input_file" | tar xf -) ;;
|
|
"tar") std_output=$(tar --extract --file="$input_file" 2>&1) ;;
|
|
"unar")
|
|
std_output=$(unar -- "$input_file" 2>&1)
|
|
exit_code=$?
|
|
|
|
if ((exit_code != 0)) && grep -i -q "requires a password" <<<"$std_output"; then
|
|
local password=""
|
|
__temp_dir_exit && __temp_dir_remove
|
|
password=$(__get_password) || exit 1
|
|
__temp_dir_cd
|
|
std_output=$(unar -force-overwrite -password "$password" -- "$input_file" 2>&1)
|
|
exit_code=$?
|
|
fi
|
|
;;
|
|
"unrar")
|
|
std_output=$(unrar x -p"null" -- "$input_file" 2>&1)
|
|
exit_code=$?
|
|
|
|
if ((exit_code != 0)) && grep -i -q "incorrect password for" <<<"$std_output"; then
|
|
local password=""
|
|
__temp_dir_exit && __temp_dir_remove
|
|
password=$(__get_password) || exit 1
|
|
__temp_dir_cd
|
|
std_output=$(unrar x -p"$password" -- "$input_file" 2>&1)
|
|
exit_code=$?
|
|
fi
|
|
;;
|
|
"unsquashfs") std_output=$(unsquashfs "$input_file" 2>&1) ;;
|
|
"unzip")
|
|
std_output=$(unzip -P "null" -- "$input_file" 2>&1)
|
|
exit_code=$?
|
|
|
|
if ((exit_code != 0)) && grep -i -q "incorrect password" <<<"$std_output"; then
|
|
local password=""
|
|
__temp_dir_exit && __temp_dir_remove
|
|
password=$(__get_password) || exit 1
|
|
__temp_dir_cd
|
|
std_output=$(unzip -P "$password" -- "$input_file" 2>&1)
|
|
exit_code=$?
|
|
fi
|
|
;;
|
|
"xorriso") std_output=$(xorriso -osirrox on -indev "$input_file" -- -extract / . -rollback_end 2>&1) ;;
|
|
"xz") std_output=$(xz -d -c -k -- "$input_file" >"$filename") ;;
|
|
"zpaq") std_output=$(zpaq x "$input_file" 2>&1) ;;
|
|
"zstd") std_output=$(zstd -d -c -- "$input_file" >"$filename") ;;
|
|
"bsdtar+unar+7za")
|
|
exit_code=1
|
|
|
|
# Try to extract with 'bsdtar'.
|
|
if ((exit_code != 0)); then
|
|
std_output=$(bsdtar -xf "$input_file" 2>&1)
|
|
exit_code=$?
|
|
fi
|
|
|
|
# Try to extract with 'unar'.
|
|
if ((exit_code != 0)); then
|
|
std_output=$(unar -- "$input_file" 2>&1)
|
|
exit_code=$?
|
|
fi
|
|
|
|
# Try to extract with '7za'.
|
|
if ((exit_code != 0)); then
|
|
std_output=$($command_7za x -aoa -- "$input_file" 2>&1)
|
|
exit_code=$?
|
|
fi
|
|
|
|
if ((exit_code != 0)); then
|
|
std_output="Could not recognize the archive format."
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
# Check for result errors.
|
|
local exit_code_last=$?
|
|
if ((exit_code != 0)) || ((exit_code_last != 0)); then
|
|
_check_output "1" "$std_output" "$input_file" ""
|
|
|
|
# If all extracted files have zero bytes, then abort.
|
|
local non_zero_files=""
|
|
non_zero_files=$(find . -type f ! -size 0 2>/dev/null)
|
|
if [[ -z "$non_zero_files" ]]; then
|
|
__temp_dir_exit && __temp_dir_remove
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Fix permissions of extracted files in "iso" archive format.
|
|
if [[ "${input_file,,}" == *".iso" ]]; then
|
|
chmod --recursive u+rw -- .
|
|
fi
|
|
|
|
# Check if the archive has just one item (single file/directory compressed).
|
|
local count_root_items=""
|
|
local single_root_item=""
|
|
count_root_items=$(find . -mindepth 1 -maxdepth 1 2>/dev/null | wc -l)
|
|
if ((count_root_items == 1)); then
|
|
single_root_item=$(find . -mindepth 1 -maxdepth 1 2>/dev/null)
|
|
single_root_item="${single_root_item#./}"
|
|
fi
|
|
|
|
# Check if the 'temp_dir_output' is empty.
|
|
if ((count_root_items == 0)); then
|
|
__temp_dir_exit && __temp_dir_remove
|
|
exit 1
|
|
fi
|
|
|
|
__temp_dir_exit
|
|
|
|
# Move the items to the correct directory.
|
|
if [[ "$single_root_item" == "$filename" ]] || [[ "$(_strip_filename_extension "$single_root_item")" == "$filename" ]]; then
|
|
# For archives with "one item with the same name of the archive".
|
|
# For example: "README.txt.tar.gz" or "README.tar.gz".
|
|
std_output=$(_move_file "rename" "$temp_dir_output/$single_root_item" "$output_dir/$single_root_item" 2>&1)
|
|
_check_output "$?" "$std_output" "$input_file" ""
|
|
elif [[ "$single_root_item" == "squashfs-root" ]] && [[ "$command" == "unsquashfs" ]]; then
|
|
# For the "squashfs" archive format.
|
|
std_output=$(_move_file "rename" "$temp_dir_output/$single_root_item" "$output_dir/$filename" 2>&1)
|
|
_check_output "$?" "$std_output" "$input_file" ""
|
|
else
|
|
# For archives with "one item with a different name of the archive" or "multiple items".
|
|
std_output=$(_move_file "rename" "$temp_dir_output" "$output_dir/$filename" 2>&1)
|
|
_check_output "$?" "$std_output" "$input_file" ""
|
|
fi
|
|
|
|
__temp_dir_remove
|
|
}
|
|
|
|
_all_commands_exists() {
|
|
local commands=$1
|
|
|
|
local command=""
|
|
local commands_array=()
|
|
IFS=" " read -r -a commands_array <<<"$commands"
|
|
|
|
for command in "${commands_array[@]}"; do
|
|
if ! _command_exists "$command"; then
|
|
return 1
|
|
fi
|
|
done
|
|
return 0
|
|
}
|
|
|
|
_main "$@"
|