loop for file location until file exists in bash

842 views Asked by At

I have created this function:

function promptFile()

{

while true;
    do
            read -p "Please provide a full path [q to quit]: " file
            if [ $file == q ]; then
                    echo "Exiting.."
                    return 1
            fi

            if [ ! -f $file ]; then
                    echo "File does not exist, please try again"

            else
                    echo $file
                    break
            fi
    done
}

To prompt a user for file location, ask again if file does not exist, and save the output to a variable if it does, the function is called:

tempLoc=$(promptFile)
if [ !tempLoc ]; then
        fileLocation=$tempLoc
fi

Everything works well unless someone write a bad file location, then the echo is not shown until someone clicks q or inputs an existing file location. in which case the echo message will be printed * the number of bad inputs, as follows.

[root@tsting:0]# ./tst
Please provide a full path [q to quit]: tst1
Please provide a full path [q to quit]: tst2
Please provide a full path [q to quit]: tst3
Please provide a full path [q to quit]: tst4
Please provide a full path [q to quit]: q
File does not exist File does not exist File does not exist File does not exist Exiting..
[root@tsting:0]#

I'm guessing this happens because the loop collapses back printing all the echos as it happens, is there a way to avoid this and just print the echo when the wrong file location is entered ?

2

There are 2 answers

2
123 On BEST ANSWER

Write the error to stderr

echo "File does not exist, please try again" >&2

You are saving all output from the function into the variable tempLoc, so even if the user inputs a valid file it will have a load of junk in the variable with it.

Stderr is where error messages should go anyway though, so it's good practice to send them there even without this problem.

0
cdarke On

Several things here:

You don't need () with "function" (and visa versa). () is usually preferred, (except in Korn shell).

ALWAYS write error messages to stderr: >&2, that is the main reason why it does not work. There are TWO instances where this is required.

Nothing to do with your issue, but it is a good idea to quote variable values, especially filenames: "$file". This is in case someone has whitespace in the filename. Not that anyone in their right mind would ever name a file or directory with an embedded space (Program Files). Using [[ ]] rather than single brackets reduces the need, but does not remove it altogether.

Always declare variables inside functions as local, unless you really need to use a global (which you usually don't). If you don't do that then the variables inside a function could stomp on those outside, particularly if you reuse the function in several scripts.

The if statement after calling the function is incorrect. You are testing for true/false (which it won't be) and you have omitted a $ prefix.

promptFile()
{
    local file

    while true
    do
        read -p "Please provide a full path [q to quit]: " file
        if [ "$file" == q ]; then
            echo "Exiting.." >&2
            return 1
        fi

        if [ ! -f "$file" ]; then
            echo "File does not exist, please try again" >&2
        else
            echo "$file"
            break
        fi
    done
}

tempLoc=$(promptFile)
if [ -n "$tempLoc" ]; then
   fileLocation=$tempLoc
fi