So I need my while loop to continually loop but it stops after the first user's input, example:
[user]$: ./pleasefix.sh
Enter Input:test
test is writeable.
[user]$:
Heres my script as it is:
if [ "$#" -ne 0 ]
then
echo "$0" "is expecting no arguments; found $# $*"
echo "Usage: "$0""
exit 2
fi
while read -p "Enter Input:" userString
do
if [ -w "$userString" ]
then
echo ""$userString" is writeable."
exit 0
else
echo ""$userString" is nonexistent or not writeable."
exit 1
fi
done
What can I add to my while to make it actually loop and re prompt the user for another file name? Basically I want it to last forever until a EOF is sent (crtl + D)
Take the exit 0 and exit 1 out
You are using "exit" at both case if-else. You can remove one of them.
Remove the "exit 0" and the "exit 1"? Those will cause it to exit your script.
Related
I have script
#!/bin/bash
set -e
if [[ ! $(asd) ]]; then
echo "caught command failure with exit code ${?}"
fi
echo "end of script"
purpose of script is to terminate execution on any non zero command exit code with set -e except when command is "caught" (comming from Java) as in case of bad command asd
if [[ ! $(asd) ]]; then
echo "caught command failure with exit code ${?}"
fi
however, though I "catch" the error and end of script prints to terminal, the error code is 0
echo "caught command failure with exit code ${?}"
so my question is how can I "catch" a bad command, and also print the exit code of that command?
edit
I have refactored script with same result, exit code is still 0
#!/bin/bash
set -e
if ! asd ; then
echo "caught command failure with exit code ${?}"
fi
echo "end of script"
Just use a short-circuit:
asd || echo "asd exited with $?" >&2
Or:
if asd; then
:
else
echo asd failed with status $? >&2
fi
You cannot do if ! asd, because ! negates the status and will set $? to 0 if asd exits non-zero and set $? to 1 if asd exits 0.
But note that in either case best practice is to simply call asd. If it fails, it should emit a descriptive error message and your additional error message is just unnecessary verbosity that is of marginal benefit. If asd does not emit a useful error message, you should fix that.
how can I "catch" a bad command, and also print the exit code of that command?
Often enough I do this:
asd && ret=$? || ret=$?
echo asd exited with $ret
The exit status of the whole expression is 0, so set -e doesn't exit. If asd succedess, then the first ret=$? executes with $? set to 0, if it fails, then the first ret=$? is omitted, and the second executes.
Sometimes I do this:
ret=0
asd || ret=$?
echo asd exited with $ret
which works just the same and I can forget if the && or || should go first. And you can also do this:
if asd; then
ret=0
else
ret=$?
fi
echo asd exited with $ret
A bash script executes several commands.
After each command, how to:
if success: show a custom message in the console and append it to a log file
if error: show the error message in the console, append error message to the log file and resume the entire script
Here is where I am:
log_file="log.txt"
output() {
echo $#
echo $# 2>&1 >> $log_file;
if [ $# -eq 0 ]
then
exit 1
fi
}
and then after each command:
if [ $? -eq 0 ]
then
output "Custom message"
else
output $?
fi
Which makes lots of repetitions…
You could create a "run" function to limit repetition:
run()
{
message="$1"
shift
eval "$*"
if [ $? -eq 0 ]; then
output "$message"
else
output $?
fi
}
And simply prefix every command with:
run "message" "command"
The command only needs to be quoted if it contains shell meta-expressions.
Here's a way to accomplish that; after each command to be tracked, add this line:
rc="$?"; if [ "$rc" -eq 0 ]; then echo "Custom message" 2>&1 | tee -a /folder/log; else echo "$rc" 2>&1 | tee -a /folder/log; fi
The following command will give you the exit status of your last run command.
$?
e.g lets say you executed "ls" command , after that if you execute the following
echo $?
you will see the exit status as 0. which means successful . An Non-zero exit status means failure.
You can use this in some sort of if else in your shell script and based on the exit value do whatever you need to do.
Lets say a program that outputs a zero in case of success, or 1 in case of failure, like this:
main () {
if (task_success())
return 0;
else
return 1;
}
Similar with Python, if you execute exit(0) or exit(1) to indicate the result of running a script. How do you know what the program outputs when you run it in shell. I tried this:
./myprog 2> out
but I do not get the result in the file.
There's a difference between an output of a command, and the exit code of a command.
What you ran ./myprog 2> out captures the stderr of the command and not the exit code as you showed above.
If you want to check the exit code of the a program in bash/shell you need to use the $? operator which captures the last command exit code.
For example:
./myprog 2> out
echo $?
Will give you the exit code of the command.
BTW,
For capturing the output of a command, you may need to use 1 as your redirect where 1 captures stdout and 2 captures stderr.
The returnvalue of a command is stored in $?. When you want to do something with the returncode, it is best to store it in a variable before you call another command. The other command will set a new returncode in $?.
In the next code the echo will reset the value of $?.
rm this_file_doesnt_exist
echo "First time $? displays the rm result"
echo "Second time $? displays the echo result"
rm this_file_doesnt_exist
returnvalue_rm=$?
echo "rm returned with ${returnvalue}"
echo "rm returned with ${returnvalue}"
When you are interested in stdout/stderr as well, you can redirect them to a file. You can also capture them in a shell variable and do something with it:
my_output=$(./myprog 2>&1)
returnvalue_myprog=$?
echo "Use double quotes when you want to show the ${my_output} in an echo."
case ${returnvalue_myprog} in
0) echo "Finally my_prog is working"
;;
1) echo "Retval 1, something you give in your program like input not found"
;;
*) echo "Unexpected returnvalue ${returnvalue_myprog}, errors in output are:"
echo "${my_output}" | grep -i "Error"
;;
esac
I'm writing a simple shell script that should exit with 0 if an input string is found in a file, and exit with 1 if it isn't
INPSTR=$1
cat ~/file.txt | while read line
do
if [[ $line == *$INPSTR* ]]; then
exit 0
fi
done
#string not found
exit 1
What's actually happening is that when the string is found, the loop exits, and the shell then goes to "exit 1". What's the correct way to exit from the shell script entirely while in a loop?
You need to avoid creating sub-shell in your script by avoiding the pipe and un-necessary cat:
INPSTR="$1"
while read -r line
do
if [[ $line == *"$INPSTR"* ]]; then
exit 0
fi
done < ~/file.txt
#string not found
exit 1
Otherwise exit 0 is only exiting from the sub-shell created by pipe and later when loop ends then exit 1 is used from parent shell.
you can catch return code of subshell using $? like this
INPSTR=$1
cat ~/file.txt | while read line
do
if [[ $line == *$INPSTR* ]]; then
exit 0
fi
done
if [[ $? -eq 0 ]]; then
exit 0
else
#string not found
exit 1
fi
I want to completely terminate/exit a bash shell script upon error, but using a function error that lets me display a debug output before termination. Now I have the problem that the exit 1 statement inside the error function will not terminate the shell script if the function's output is captured via backticks or $().
Here is my sample script:
#!/bin/bash
function error ()
{
echo "An error has occured: $1"
exit 1
}
function do_sth ()
{
if [ $1 -eq 0 ]; then
error "First param must be greater than 0!"
else
echo "OK!"
fi
}
RESULT=`do_sth 0`
echo "This line should never be printed"
How can I immediately terminate the script in the error() function?
The problem with command substitution is, that a subshell is started to execute do_sth. exit 1 then terminates this subshell and not the main bash.
You can work around this by appending || exit $?, which exits with the exit code from the command substitution
RESULT=`do_sth 0` || exit $?
If you want to show the error message, redirect it to stderr
echo "An error has occured: $1" >&2
RESULT=`do_sth 0` || exit $?
then
echo "An error has occured: $1" >&2
There's no way to avoid the fact that the subshell cannot make the parent terminate directly: the parent will have to evaluate the value returned from the subshell. A common technique is to trap exit and print an error message in the trap function. Since you are generating the error message in a subshell, you cannot simply assign the message to a variable as otherwise might be done, but you can use the filesystem. Please note that this idea is really silly, and it is much cleaner to simply write error messages to stderr. That's what it is for, and that's why it is inherited by children. Something like:
#!/bin/sh
trap final 0 2 15
# Create a temporary file to store error messages. This is a terrible
# idea: it would be much better to simply write error messages to stderr,
# but this code is attempting to demonstrate the technique of having the
# parent print the message. Perhaps it would do better to serve as an example
# of why reporting your children's mistakes is a bad idea. The children
# should be responsible for reporting their own errors. Doing so is easy,
# since they inherit file descriptor 2 from their parent.
errmsg=$( mktemp xxxxx )
final() {
test "$?" = 0 || cat $errmsg
rm -f $errmsg
} >&2
# Must emphasize one more time that this is a silly idea. The error
# function ought to be writing to stderr: eg echo "error: $*" >&2
error() { echo "error: $*" > $errmsg; exit 1; }
do_sth() {
if test "$1" -eq 0; then
error "First param must be greater than 0!"
else
echo "OK!"
fi
}
result=$( do_sth 0 ) || exit 1
echo not printed
It seems the (clever) answer is on another question's top answer by #FatalError, here on so
This should work...
#!/bin/bash
trap "exit 1" 50 #exit process after receiving signal 50.
function myerror ()
{
echo "An error has occured: $1" >&2
}
function do_sth ()
{
if [ $1 -eq 0 ]; then
myerror "First param must be greater than 0!"
kill -50 $(ps --pid $$ -opid=) #uncommon signal 50 is used.
else
echo "OK!"
fi
}
RESULT=`do_sth 1`
echo $RESULT
RESULT=`do_sth 0`
echo $RESULT
echo "This line should never be printed"