I'm trying to zip and unzip files with a bash script, but I'm new and I have problems. I will explain what the script currently does, and then what I wanted it to do.

  • User selects “compress”: a file dialog appears, showing all files. The user selects a file (e.g. /home/ubuntu/file.txt). The file is compressed and saved to /home/ubuntu as file.zip that contains /home/ubuntu/file.txt.

  • User selects “decompress”: a file dialog appears, showing all files. The user selects a file (e.g. /home/ubuntu/file.zip. The file is

Now what I want from the script to do:

  1. After compressing a file, I want the directory of that compressed file to be the same. For example, for /home/ubuntu/filename.txt, I want it to be saved in /home/ubuntu/ as filename.zip. I want it to contain only filename.txt inside and not /home/ubuntu/filename.txt or home/ubuntu/filename.txt.
  2. On decompression, I want the file dialog to show only *.zip files, so that the user could not select an file this is uncompressed.
  3. On decompression, I want to know where the file is saved.

Here is my code:

#! /bin/bash
#This bash compresses and decompresses files
act=-1 #A variable used to transfer which action has been  chosen
action2="Decompress"  #action1 & 2 both used for certain echoes

function menu { #The menu
    local title="-------Menu-------"
    local prompt="Please choose an action:"
    local options=("$action1" "$action2" "Quit")

    echo "$title"
    PS3="$prompt" #Changes the default '#?' that the select command uses to $prompt.
    select option in "${options[@]}";do

        case $option in

            echo "You chose $option"
            act=0 #Changes act to 0 , to be used later      

            echo "You chose $option"
            act=1 #Changes act to 1 , to be used later              
            echo "You chose $option"
            echo "Invalid option please choose between 1-3"

function ynPrompt { #a y/n prompt to go back to the main menu or exit
    while true #helps to loop the y/n prompt in case of wrong input ex. a343

        read -r -p "Do you want to go back to the menu? [y/N] " response
        case $response in

             [yY][eE][sS]|[yY]) #accepts yes or y and ignores casing ex. yEs is accepted.
             continue 2     #continues the outer control loop
             [nN][oO]|[nN])     #accepts no or n and ignores casing ex. nO is accepted.     
             exit           #exits the script   
             continue           #shows the message again

function main { #Performs the selected action
    if [ $act -eq 0 ]; then

        if zip -r ${path}.zip ${path}   
        then echo Compression successful
        echo $? #prints 0 
        else echo $? 

        #echo "$action1"
        #zip -r ${path}.zip ${path}

    elif [ $act -eq 1 ]; then

        if unzip ${path} 
        then echo Decompression successful
        echo ${path}
        echo $? #prints 0
        else echo $?

        #echo "$action2"
        #unzip ${path}

        echo "$error"


#~~~~~~~~~~~~ Script start ~~~~~~~~~~~~~~~~
while true #outer control loop
    menu #call menu
    cd /home
    path=$(zenity --file-selection) #Stores the path of the file into path variable through zenity dialog 
#path can only be .zip if i had --file filter *.zip

    if [ -z $path ]; then  #checks length of $path , returns true if length = 0 
        ynPrompt #call ynprompt
        main     #call main

  • 1
    You should describe your problem / question more precisely. It seems to me that your code is not relevant for the task you have described. – Hauke Laging Dec 25 '15 at 2:26
  • ditto - but since you posted it anyway, just let me say that the few kinds of read prompt programs that aren't 100% annoying would never insist on y/yes/n/no RETURN in a forever loop. just read a byte, compare it to Y/y and abort for anything else. definitely narrow the ok the case, and default to cowardice. its the best way. – mikeserv Dec 25 '15 at 2:49

You can use this for compression:

compress_file () 
    local dir file
    test -f "$1" || return 2
    dir="$(readlink -f "$1")"
    cd "$dir"
    # check whether target file exists:
    # test -f "$file".zip && : whatever
    echo zip "$file".zip "$file"

compress_file /path/to/file

file selection for decompression

I am not familiar with zenity. It seems that it cannot filter files. You can approach the disired effect by creating a temporary directory, linking only the *.zip files into it and run zenity for this directory. Of course, if the user selects a different directory then he will see all files.

zipfile_dialog () 
    local file startdir="/home/ubuntu" tmpdirname=.zipscript.$$
    cd "$startdir" || return 2
    test -d "$tmpdirname" && { rm -r "$tmpdirname" || return 2; }
    mkdir -p "$tmpdirname" || return 2
    for file in *.zip; do
        cd "$tmpdirname"
        ln -s ../"$file"
        cd ..
    ls "$tmpdirname"
    # call zenity here
    rm -r "$tmpdirname"


An alternative approach would be to use the shell for file selection. That could be done with programmable completion if that is an option for you (complete, compgen).

  • can you add some comments on the code? – Alex Andreadis Dec 25 '15 at 11:25
  • @AlexAndreadis What don't you understand? Seems very simple to me. – Hauke Laging Dec 25 '15 at 11:50
  • where to use them on my code?? I cant understand. – Alex Andreadis Dec 25 '15 at 20:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.