linuxbashcompressionmultiple-arguments

How to pass a variable which has multiple arguments to function all at once?


I am trying to make a command which allows the user to input a name as the first argument for the compressed file they want to create (which will become a tar.gz file) and file and directory names as the second argument.

So far I have this script

name_of_archive=$1
directory_or_file_paths=$2

if [ $# -eq 0 ]
then
        echo "Usage: $0 [name of archive you wish to create] [path of directories or files you wish to compress]"
        echo "You must enter atleast one file or directory name"
        exit 1
else
        if [ -e "$directory_or_file_paths" ] || [ -d "$directory_or_file_paths" ]
        then
                tar -czvf "$name_of_archive".tar.gz "$directory_or_file_paths"
                echo "The filenames or directories you specified have been compressed into an archive called $name_of_archive.tar.gz"
        else
                echo "Some or all of the file or directory names you have given do not exist"
        fi
        exit
fi

This is what I get when I use the command:

compression2.bash compression1 ./test ./listwaste
./test/
./test/test2/
./test/test2/2
./test/1
The filenames or directories you specified have been compressed into an archive called compression1.tar.gz

The first is a directory and the second is a file. It works if I attempt to compress both individually but does not work if I try to compress more than one file or directory or a mix at a time. I would like it to be able to do that.


Solution

  • It is not a good idea to store filenames in a string. Storing them in an array is a much better approach:

    #!/usr/bin/env bash
    
    [[ $# -lt 2 ]] && exit 1
    
    name=$1; shift
    files=("$@")
    
    #exclude all files/directories that are not readable
    for index in "${!files[@]}"; do
       [[ -r ${files[index]} ]] || unset "files[index]"
    done
    
    [[ ${#files[@]} -eq 0 ]] && exit 1    
    
    if tar -czvf "${name:-def_$$}.tar.gz" "${files[@]}"; then
       echo "Ok"
    else
       echo "Error"
       exit 1
    fi
    

    shift; files=("$@") discards the first argument (name) and saves the rest of the arguments (filenames) into an array.


    You could also construct the array of filenames for tar with a more straightforward approach:

    name=$1; shift
    
    for file; do
       [[ -r $file ]] && files+=("$file")
    done