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
Related
I have a project to execute a script and need to format the output, including unexpected errors. I know that I can use trap to intercept errors, so I tried to use it to format the output, the example is as follows
#!/bin/bash
set -o errtrace
status=false
trap "print " ERR
print() {
echo "{\"status\":$status,\"result\":\"$1\"}"
exit 0
}
main(){
arg=$1
if [ "$arg" == "0" ];then
status=true
print "successfully finish"
else
cat /a/b/c/d >>/dev/null
echo "abnormal termination"
fi
}
main "$#"
The logic of success meets my needs as follows
# bash format-print.sh 0
{"status":true,"result":"successfully finish"}
But when an exception error is caught it doesn't meet my needs
# bash format-print.sh 1
cat: /a/b/c/d: No such file or directory
{"status":false,"result":""}
I would like to enter the following result
# bash format-print.sh 1
cat: /a/b/c/d: No such file or directory
{"status":false,"result":"cat: /a/b/c/d: No such file or directory"}
How can I modify the code to meet my needs, and if trap does not work or is not the standard way, can you please tell me how to implement it?
It sounds like what you need is to capture the error output from your command so that you can include it in your formatted output. You don't need a trap for this, although if you wanted to use a trap to invoke print you could do that (maybe with EXIT instead of ERR though).
With direct calls to the print function, this will do what you're looking for:
#!/bin/bash
set -o errtrace
status=false
#trap "print " ERR # removed trap for testing
print() {
echo "{\"status\":$status,\"result\":\"$1\"}"
exit 0
}
main(){
arg=$1
if [ "$arg" == "0" ];then
status=true
print "successfully finish"
else
# captures stderr into a variable while discarding stdout
result=$( cat /a/b/c/d 2>&1 >/dev/null )
print "$result"
fi
}
main "$#"
This will provide the output:
$ ./test.sh 1
{"status":false,"result":"cat: /a/b/c/d: No such file or directory"}
I am writing a script in BASH. I have a function within the script that I want to provide progress feedback to the user. Only problem is that the echo command does not print to the terminal. Instead all echos are concatenated together and returned at the end.
Considering the following simplified code how do I get the first echo to print in the users terminal and have the second echo as the return value?
function test_function {
echo "Echo value to terminal"
echo "return value"
}
return_val=$(test_function)
Yet a solution other than sending to STDERR (it may be preferred if your STDERR has other uses, or possibly be redirected by the caller)
This solution direct prints to the terminal tty:
function test_function {
echo "Echo value to terminal" > /dev/tty
echo "return value"
}
-- update --
If your system support the tty command, you could obtain your tty device from the tty command, and thus you may:
echo "this prints to the terminal" > `tty`
send terminal output to stderr:
function test_function {
echo "Echo value to terminal" >&2
echo "return value"
}
Dont use command substitution to obtain the return value from the function
The return value is always available at the $? variable. You can use the variable rather than using command substitution
Test
$ function test_function {
> return_val=10;
> echo "Echo value to terminal $return_val";
> return $return_val;
> }
$ test_function
Echo value to terminal 10
$ return_value=$?
$ echo $return_value
10
If you don't know in which terminal/device you are:
function print_to_terminal(){
echo "Value" >$(tty)
}
I'm looking to create a one-line command which does some stuff and gets a value (which would generally be output) and instead turn that into an exit code (so I can trigger a subsequent step which responds to non-zero exit codes).
For example, running something like this:
echo 5 | exit
And then having a subsequent echo $? output 5, the value I gave it earlier.
The above syntax doesn't work. Is there a way to achieve this?
Assuming:
cmd() { echo 5; }
For a literal answer:
cmd | (read -r rc && exit "$rc")
However, you can also run:
( exit "$(cmd)" ) # parens create a subshell so we aren't exiting the main shell
You can just use command substitution:
( exit $(cmd) )
Assuming cmd is returning an integer between 0-255
An example:
$> ( exit $(echo 5) )
$> echo $?
5
Below is the code of bash:
a=`echo hello`
echo $a
output is :
hello
But I think it should be:
hello
0
You think wrong ;-)
Putting the command in backticks assigns the output (stdout) from the expression on the right to the variable on the left.
$? gives you the "output status" (or return code) of the command - aka the "0" you were expecting.
So:
a=`echo hello`
Runs the command "echo hello" but instead of echoing to stdout, it "echoes" to varaiable a. So a=whatever_the_command_would_have_written_to_stdout (in this case "hello") - nothing is actually written to stdout because it is "captured" by the ``s
You mistakenly think that a=`echo hello`:
executes echo hello and prints its stdout output directly to the caller's stdout,
and then assigns the exit code (return value) of the echo command to variable $a.
Neither is true; instead:
echo hello's stdout output is captured in memory (without printing to the caller's stdout; that's how command substitutions work),
and that captured output is assigned to $a.
A command's exit code (a return value indicating success vs. failure) is never directly returned in POSIX-like shells such as Bash.
The only way to use an exit code is either:
explicitly, by accessing special variable $? immediately after the command ($? contains the most recent command's exit code)
implicitly, in conditionals (a command whose exit code is 0 evaluates to true in a conditional, any other exit code implies false).
Thus, to achieve what you're really trying to do, use:
echo 'hello' # Execute a command directly (its stdout output goes to the caller's stdout)
a=$? # Save the previous command's exit code in var. $a
echo "$a" # Echo the saved exit code.
As this [ this ] answer already mentioned, the return value for the last executed command is stored in
$? # ${?} is sometimes needed
If you wish a to contain 'hello' and the return value of echo hello in separate lines, ie
hello
0
below is one way to do it
$ a=`echo -en "hello\n" && echo -n $?` # here $? is ret val for 1st echo
$ echo -e "$a"
hello
0
Note
-n with echo suppresses the trailing new line
-e with echo interprets escape sequences
Since && is the logical and operator, the second echo wouldn't have been executed had the first echo failed
Another important point to note is that even the assignment ie
a=b
has a return value.
I have two simple scripts:
#!/bin/sh
echo "this script return sth"
exit 105
and:
#!/bin/sh
echo "this script will print last script return"
echo "first run a script"
./this_script_return_sth.sh
echo "previous script return value: $?"
echo $?
the run result is:
this script will print last script return
first run a script
this script return sth
previous script return value: 105
0
anything I did wrong? does it means that if I want to use it, it better to first store it to some variable?
$? expands to the last statement's return code. So, the zero says the last echo statement (i.e. echo "previous script return value: $?") was sucessful.
From bash manual:
?
($?) Expands to the exit status of the most recently executed foreground pipeline.
If you need the value in multiple places, then you can always store in a variable:
./this_script_return_sth.sh
rc=$?
echo "previous script return value: $rc"
echo $rc
$? always returns the status code for the last executed shell command.
In your case, the last line of your script:
echo $?
prints the return code for the last executed command which is:
echo "previous script return value: $?"
And not the script.
$? return the exit status of the last command executed.
Every command returns an exit status (sometimes referred to as a return status or exit code). A successful command returns a 0, while an unsuccessful one returns a non-zero value that usually can be interpreted as an error code.
In your first script, you are sending 105 as exit code, so it printed :
previous script return value: 105
And next line, echo $? returned 0 for successful execution of last command.
Your scripts are working as expected.
For more details, refer Exit status