Marko
Marko

Reputation: 417

How to catch a variable from a function and sent it as a parameter to another function?

I use in a function a variable that was defined in another function, from the same script, but I receive an error.

  testare()
{
        find "$Home" -name "$({!i})"
        rez=$?
        test -d "$rez"
        t1=$?
        test -f "$rez"
        t2=$?

        if [ "$t1" -eq 0 ]
        then
                return 0
        elif [ "$t2" -eq 0 ]
        then
                return 1
        else
                return 2
        fi
}

menu ()
{
        if [ "$#" -lt 2 ] || [ "$#" -gt 9 ]
        then
                echo "Error!"
                return
        fi

        for (( i=2; i <= "$#"; ++i ))
        do
                testare "$({!i})"
                rez=$?

                if [ "$rez" -eq 0 ]
                then
                        echo "Director with the same name exists!"
                fi

                if [ "$rez" -eq 1 ]
                then
                        echo "File with the same name already exists!"
                fi

                if [ "$rez" -eq 2 ]
                then
                        touch "$({!i})"
                fi
        done
}

menu $@

What my code should do: I call my script with maximum 9 parameters, the first one indicates the location where i must create files with the names of the other parameters. First i have to check if those names arent already present on my disc. The usage of FOR is mandatory.

The error shows up on the **** line, because of the i variable. I think " i " isnt available at that moment. How could I make this work? :(

I tried also with writing in another file the function and source it on menu, same result..

Upvotes: 1

Views: 179

Answers (2)

assefamaru
assefamaru

Reputation: 2789

You can eliminate testare and simply perform the script's function in one routine as follows:

#!/bin/bash

menu() {
    if [ "$#" -lt 2 ] || [ "$#" -gt 9 ]; then
        echo "Error!"
        exit 1
    fi
    for (( i = 2; i <= "$#"; i++ )); do
        if [ -d "$1/${!i}" ]; then
            printf "Directory '%s' already exists! \n" "${!i}"
        elif [ -f "$1/${!i}" ]; then
            printf "File '%s' already exists! \n" "${!i}"
        else 
            touch "$1/${!i}"
        fi
    done
    exit 0
}

menu "$@"

But if you want to use the two routines as they are, then you can modify your script as follows:

testare() {
    test -d "$1/$2"
    t1="$?"
    test -f "$1/$2"
    t2="$?"

    if [ "$t1" -eq 0 ]; then
        return 0
    elif [ "$t2" -eq 0 ]; then
        return 1
    else
        return 2
    fi
}

menu() {
    if [ "$#" -lt 2 ] || [ "$#" -gt 9 ]; then
        echo "Error!"
        exit 1
    fi
    for (( i = 2; i <= "$#"; i++ )); do
        testare "$1" "${!i}"
        rez="$?"

        if [ "$rez" -eq 0 ]; then
            printf "Directory '%s' already exists! \n" "${!i}"
        elif [ "$rez" -eq 1 ]; then
            printf "File '%s' already exists! \n" "${!i}"
        else
            touch "$1/${!i}"
        fi
    done
    exit 0
}

menu "$@"

Remember: when you are passing any variable as an argument, that parameter to the routine is accessed by $i where i is replaced by any number >=0 referring to the position of the argument from left to right.

For example, in your script, you had $({!i}) within testare, but the variable i is only defined in the menu routine, hence using that variable in testare results in errors. In order access the arguments passed to testare, you should either directly access them, ie. $1, $2 etc. or you should define a variable (in a loop, for example) and access them using that variable as ${!j} for some variable j.


Edit- explanation for first comment's questions:

Consider, for example, that you had an empty folder named dir in your current working directory. Now you want to create files one, two and three in the dir folder. Hence, you pass it to your script as:

$ ./script dir one two three

Thus, "$1"=dir, "$2"=one etc. The line test -d "$1/$2" tests whether $2 is a directory and exists within the $1 folder, ie. whether or not dir/one exists and is a directory. This is necessary because all files need to be tested and created within the specified directory, which always comes as the first argument to the script (as you stated).

In your script, since testare is doing the testing for existence of named file/directory, testare will need access to the dir directory, hence the reason for 2 arguments being passed to testare in the line testare "$1" "${!i}", whereby the first argument is the dir directory, and the second argument is the file to be tested.

As for your question on how many arguments a method should be called with, you should pass on as many arguments as needed to make the routine do what it is supposed to. For example, the routine testare needed to have the dir directory and some specified file, so that it can check whether that file exists within dir. Hence calling testare dir somefile by using testare "$1" "${!i}".

On the other hand, the %s in printf is a placeholder for "string", whose value is provided at the end. For example,

$ printf "This is not a placeholder for %s \n" "numbers"
This is not a placeholder for numbers
$ printf "The placeholder for numbers is %s \n" "%d"
The placeholder for numbers is %d
$ printf "pi as a whole number equals %d\n" 3
pi as a whole number equals 3

Edit 2: If you want to search the /home directory recursively to check whether somefile exists, you can do the following:

#!/bin/bash

file=$(find /home -name "somefile")

if [[ "$file" != "" ]]; then
    echo "file exists"
else
    echo "file does not exist"
fi

Upvotes: 2

SLePort
SLePort

Reputation: 15461

You can try this (comments and suggestions in the script) :

# Explicit function name
found() {
    if [[ -f "$1" ]];then
        foundtype="file"
        # found() success, return 0
        return 0
    elif [[ -d "$1" ]]; then
        foundtype="directory"
        return 0
    else
        # found() failed, return 1
        return 1
    fi
}

menu () {
    if [ $# -lt 2 ] || [ $# -gt 9 ]
    then
        # Explicit message sent to stderr
        echo "Error : you must provide from 2 to 9 parameters" >&2
        # exit script with 1 status code (failed)
        exit 1
    fi

    destdir="$1"
    shift
    # loop over params
    for file in "$@"
    do
        if found "$destdir/$file"; then # found value = found() return code
            echo "$destdir/$file" "is an existing" "$foundtype";
            continue; # next iteration
        else
            # create destination dir if doesn't exist (as dir or as file)
            [ ! -d "$destdir" ] && [ ! -f "$destdir" ] && mkdir "$destdir"
            echo "Creating $destdir/$file" &&  touch "$destdir/$file"
        fi
    done
}
menu "$@"

Upvotes: 2

Related Questions