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 ?
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.
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
来源:https://stackoverflow.com/questions/30726824/loop-for-file-location-until-file-exists-in-bash