2

I wanted to make a .zshrc alias with the help of these previous aliases present to make an alias to convert a compressed gpg to its original uncompressed folder or file... However, I am facing this issue which can not seem to find a fix.

The alias used:

# Alias to decrypt and extract a .tar.gz.gpg file
alias ungpgextract='gpg --output "${1%.gpg}" --decrypt "$1" && extract "${1%.gpg}"'

Also tried with these but they did not work:

# Alias to decrypt and extract a .tar.gz.gpg file
alias ungpgextract='output_file="${1%.gpg}"; gpg --output "$output_file" --decrypt "$1" && extract "$output_file"'

# Alias to decrypt and extract a .tar.gz.gpg file
alias ungpgextract='gpg --decrypt --output ${1%.gpg} $1 && extract ${1%.gpg}'

Error message appeared even though the dir has the folder private.tar.gz.gpg:

❯ ungpgextract private.tar.gz.gpg
gpg: can't open '': No such file or directory
gpg: decrypt_message failed: No such file or directory

These are the existing alias/function use them to your need:

# Alias's for archives
alias mktar='tar -cvf'
alias mkbz2='tar -cvjf'
alias mkgz='tar -cvzf'
alias untar='tar -xvf'
alias unbz2='tar -xvjf'
alias ungz='tar -xvzf'

# Extracts any archive(s) (if unp isn't installed)
extract() {
    for archive in "$@"; do
        if [ -f "$archive" ]; then
            case $archive in
            *.tar.bz2) tar xvjf $archive ;;
            *.tar.gz) tar xvzf $archive ;;
            *.bz2) bunzip2 $archive ;;
            *.rar) rar x $archive ;;
            *.gz) gunzip $archive ;;
            *.tar) tar xvf $archive ;;
            *.tbz2) tar xvjf $archive ;;
            *.tgz) tar xvzf $archive ;;
            *.zip) unzip $archive ;;
            *.Z) uncompress $archive ;;
            *.7z) 7z x $archive ;;
            *) echo "don't know how to extract '$archive'..." ;;
            esac
        else
            echo "'$archive' is not a valid file!"
        fi
    done
}

Please, I earnestly request you to suggest a way to solve this problem.

2 Answers 2

3

An alias is not a function, it only defines what text (if found in command position unless you use -g or -s) must be replaced by some other text.

If you define:

alias ungpgextract='gpg --output "${1%.gpg}" --decrypt "$1" && extract "${1%.gpg}"'

And later have:

ungpgextract somefile
somefunction() {
  ungpgextract whatever
}

Then alias expansion occurs, but that becomes:

gpg --output "${1%.gpg}" --decrypt "$1" && extract "${1%.gpg}" somefile
somefunction() {
  gpg --output "${1%.gpg}" --decrypt "$1" && extract "${1%.gpg}" whatever
}

Here, you want a function:

ungpgextract() {
  gpg --output $1:r --decrypt -- $1 &&
    bsdtar xvf $1:r
}

(bsdtar can extract most archive formats, including the ones in your lists that are archive formats (tar compressed by all those compression formats, zip, rar, 7z) but not the .bz2/.gz/.Z if they don't compress an archive for which you need bsdcat)

A few notes about your code:

  • errors should go to stderr

  • zsh is one of the rare shells where echo can be used for arbitrary data, but that's with echo -E - $arbitrary_data. But here, you might as well use the Korn-style print -ru2 -- $arbitrary_data (which prints raw on fd (unit) 2). Like in those 3 functions defined at once with:

    warning error info() print -ru2 -- "$0: $@"
    
  • when the extract function fails, you should return a failure exit status. Here you get a failure status if the commands it invokes fails but only for the last file if that's the last thing run in that function, not in the echo cases. You can use tar... || return to have extract return with tar's exit status if it fails and return 1 for the cases where you detect an error yourself. Or if you're happy to carry on with the rest of the positional parameters even if the previous one could be extracted, record the failure in a local variable: local ret at the start and tar... || ret=$?, print -ru2 error...; ret=1 and return ret at the end.

  • for archive in "$@"; do can be written for archive do as the positional parameters is what for loops over by default (in any Bourne-like shell, not just zsh).

  • it's good practice to use local in functions for those variables that are not intended to be global (local archive in your case).

0

I know it is more of a workaround but I was able to make it work via using functions. Here's the relevant part of my .zshrc snippets:

# Automated encryption and decryption on file/folders
mkcryptgz() {
    if [[ -d "$1" ]]; then
        tarball="${1}.tar.gz"
        tar -czf "$tarball" "$1" && gpg --output "${tarball}.gpg" --symmetric "$tarball" && rm "$tarball"
        if [[ $? -eq 0 ]]; then
            echo "Directory '$1' compressed, encrypted, and original archive removed."
        else
            echo "Error during compression or encryption."
        fi
    else
        echo "'$1' is not a valid directory!"
    fi
}

ungpgextract() {
    if [[ -f "$1" ]]; then
        output_file="${1%.gpg}"
        gpg --output "$output_file" --decrypt "$1"
        
        if [[ $? -eq 0 ]]; then
            extract "$output_file"
            if [[ $? -eq 0 ]]; then
                rm "$output_file"
                echo "Decrypted, extracted, and removed: $output_file"
            else
                echo "Extraction failed."
            fi
        else
            echo "Decryption failed."
        fi
    else
        echo "'$1' is not a valid file!"
    fi
}
1
  • 2
    Not a work-around (IMHO). functions are the preferred method in shell scripting. Use aliases for simply shortening a command, i.e. alias pd='cd $myProjDir' . Trying to chain aliases together as you would functions or scripts with pipes is ticket to mind killing frustration (-;!
    – shellter
    Commented Sep 4 at 21:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .