Zsh Scripting – Zip Folder Without Including Path and Using One Argument

scriptingzipzsh

I'm trying to make a zip function that'll do all the steps I typically do when zipping a file or folder. Say my current directory is ~, and I want to zip a folder named Folder1, whose file path is ~/Folder2/Folder1.

Issuing

cd ~/Folder2 && zip -r Folder1 Folder1 && cd -

does exactly what I want. Namely, it zips so that the output Folder1.zip does not contain folders that lead up to the folder I'm zipping (namely, /home/user/Folder2), it zips recursively, and it takes in the first argument of zip with the exact name as the file or folder I'm zipping (Folder1.zip).

So I want to make a function in my .zshrc something akin to

coolerzip() { cd /path/to/file && zip -r file file && cd - }

where it need only take in one argument, which in this case, it will be ~/Folder2/Folder1. Then Folder1 will be the name for both files in coolerzip, and I will cd right into ~/Folder2 so Folder1 lies in my current directory before zipping. Is there any way I can achieve this so that coolerzip only requires one argument rather than three?

Best Answer

The argument of the function is $1.

You can use history expansion modifiers to extract the directory part and the last component of the path: if the argument is ~/directory2/directory1 then $1:h is ~/directory2 and $1:t is directory1. (Mnemonic: head and tail.)

Use parentheses instead of braces around the function body. This way the function body runs in a subshell (a separate shell process), and variable assignments, directory changes and so on only affect the subshell.

coolerzip () (
    cd $1:h &&
    zip -r $2:h.zip $2:h
)

Other shells don't have history expansion modifiers, so you'd need something different to parse the argument. For the file name, ${1##*/} strips off all leading directory components; however, this doesn't work if there's a trailing slash in the parameter, whereas "$(basename -- "$1")" works in that case. For the leading directories, use $(dirname -- "$1"). Note that in shells other than zsh, you need to put double quotes around variable substitutions.

coolerzip () (
    name="$(basename -- "$1")"
    cd "$(dirname -- "$1")" &&
    zip -r "$name.zip" "$name"
)
Related Question