I want to set a return value once so it goes into the while loop:
#!/bin/bash
while [ $? -eq 1 ]
do
#do something until it returns 0
done
In order to get this working I need to set $? = 1
at the beginning, but that doesn't work.
I want to set a return value once so it goes into the while loop:
#!/bin/bash
while [ $? -eq 1 ]
do
#do something until it returns 0
done
In order to get this working I need to set $? = 1
at the beginning, but that doesn't work.
You can set an arbitrary exit code by executing exit
with an argument in a subshell.
$ (exit 42); echo "$?"
42
So you could do:
(exit 1) # or some other value > 0 or use false as others have suggested
while (($?))
do
# do something until it returns 0
done
Or you can emulate a do while
loop:
while
# do some stuff
# do some more stuff
# do something until it returns 0
do
continue # just let the body of the while be a no-op
done
Either of those guarantee that the loop is run at least one time which I believe is what your goal is.
For completeness, exit
and return
each accept an optional argument which is an integer (positive, negative or zero) which sets the return code as the remainder of the integer after division by 256. The current shell (or script or subshell*) is exited using exit
and a function is exited using return
.
Examples:
$ (exit -2); echo "$?"
254
$ foo () { return 2000; }; foo; echo $?
208
* This is true even for subshells which are created by pipes (except when both job control is disabled and lastpipe
is enabled):
$ echo foo | while read -r s; do echo "$s"; exit 333; done; echo "$?"
77
Note that it's better to use break
to leave loops, but its argument is for the number of levels of loops to break out of rather than a return code.
Job control is disabled using set +m
, set +o monitor
or shopt -u -o monitor
. To enable lastpipe
do shopt -s laspipe
. If you do both of those, the exit
in the preceding example will cause the while
loop and the containing shell to both exit and the final echo
there will not be performed.
false
always returns an exit code of 1.
#!/bin/bash
false
while [ $? -eq 1 ]
do
#do something until it returns 0
done
#!/bin/bash
RC=1
while [ $RC -eq 1 ]
do
#do something until it returns 0
RC=$?
done
Some of answers rely on rewriting the code. In some cases it might be a foreign code that you have no control over.
Although for this specific question, it is enough to set $? to 1, but if you need to set $? to any value - the only helpful answer is the one from Dennis Williamson's.
A bit more efficient approach, which does not spawn a new child (but is a also less terse), is:
function false() { echo "$$"; return ${1:-1}; }
false 42
Note: echo part is there just to verify it runs in the current process.
Didn't find anything lighter than just a simple function:
function set_return() { return ${1:-0}; }
All other solutions like (...)
or [...]
or false
might contain an external process call.
Old question, but there's a much better answer:
#!/bin/bash
until
#do something until it returns success
do
:;
done
If you're looping until something is successful, then just do that something in the until section. You can put exactly the same code in the until section you were thinking you had to put in the do/done section. You aren't forced to write the code in the do/done section and then transfer its results back to the while or until.
$?
can contain a byte value between 0..255. Return numbers outside this range will be remapped to this range as if a bitwise and 255 was applied.
exit value
- can be used to set the value, but is brutal since it will terminate a process/script.
return value
- when used in a function is somewhat traditional.
[[ ... ]]
- is good for evaluating boolean expressions.
Here is an example of exit
:
# Create a subshell, but, exit it with an error code:
$( exit 34 ); echo $? # outputs: 34
Here are examples of return
:
# Define a `$?` setter and test it:
set_return() { return $1; }
set_return 0; echo $? # outputs: 0
set_return 123; echo $? # outputs: 123
set_return 1000; echo $? # outputs: 232
set_return -1; echo $? # outputs: 255
Here are are examples of [ ... ]
:
# Define and use a boolean test:
lessthan() { [[ $1 < $2 ]]; }
lessthan 3 8 && echo yes # outputs: yes
lessthan 8 3 && echo yes # outputs: nothing
Note, when using $?
as a conditional, zero (0) means success, non-zero means failure.
Would something like this be what your looking for ?
#!/bin/bash
TEMPVAR=1
while [ $TEMPVAR -eq 1 ]
do
#do something until it returns 0
#construct the logic which will cause TEMPVAR to be set 0 then check for it in the
#if statement
if [ yourcodehere ]; then
$TEMPVAR=0
fi
done
You can use until
to handle cases where #do something until it returns 0
returns something other than 1 or 0:
#!/bin/bash
false
until [ $? -eq 0 ]
do
#do something until it returns 0
done
This is what I'm using
allow_return_code() {
local LAST_RETURN_CODE=$?
if [[ $LAST_RETURN_CODE -eq $1 ]]; then
return 0
else
return $LAST_RETURN_CODE
fi
}
# it converts 2 to 0,
my-command-returns-2 || allow_return_code 2
echo $?
# 0
# and it preserves the return code other than 2
my-command-returns-8 || allow_return_code 2
echo $?
# 8
Here is an example using both "until" and the ":"
until curl -k "sftp://$Server:$Port/$Folder" --user "$usr:$pwd" -T "$filename";
do :;
done