What is echo $? in linux terminal? [duplicate] - linux

This question already has answers here:
What is the $? (dollar question mark) variable in shell scripting? [duplicate]
(9 answers)
Closed 7 years ago.
I have tried those commands.
~$top
(ctrl + z)stopped the process
~$echo $?
147
~$top
(ctrl + c)killed the process
~$echo $?
0
What happened here, please explain it and why it showing some constant value. What is the meaning of those values.

$? is the return code from the last run process. 0 means no error happened. Other values represent some kind of unusual condition.
Values 128 and above usually represent some kind of signal. 147 - 128 = 19, which means the program received signal 19 (SIGSTOP on Linux). Now, normally pressing ^Z sends SIGTSTP (a different signal from SIGSTOP), which probably meant that top caught that signal, did some (probably terminal-related) cleanup, and reissued SIGSTOP to actually suspend the program.
top also caught SIGINT (which is normally issued after pressing ^C), to do cleanup and exit cleanly (with exit value 0).
You can run kill -l to see what all the signal numbers are for the current platform. Note that the numbers are different for different platforms; for example, SIGSTOP is 17 on Darwin and 19 on Linux.

echo $? returns the return value (exit status) of the last executed command (0 is usually success).

Related

what is the benefit of $? in bash [duplicate]

This question already has answers here:
What is the $? (dollar question mark) variable in shell scripting? [duplicate]
(9 answers)
Meaning of $? (dollar question mark) in shell scripts
(8 answers)
Closed 2 years ago.
I'm new in variable concept in bash and I have seen some courses how to use and when to use special variable like $# to see how many arguments were passed in bash script and $# to see all the arguments supplied to the Bash script.
but I haven't understood $? and they just say that $? (The exit status of the most recently run process) and also I haven't got anything.
I need a little explanation and please give an example.
That definition you gave, i.e. the exit status of the most recently run process, is exactly what is is; but if you don't get how processes and commands in general work on the command line, I can understand how that might be a bit confusing.
In general, any command you run on the command line will have an exit code. In something like C/C++, you might have seen it as the return 0; appended at the end of every main() routine, and in shell scripts you might have seen it as exit 0. These return codes are the primary way to signal to the external environment (in this case the terminal) that things either ended well, or they didn't.
This is where $? comes into play. The convention on Unix systems is to have a process return exit code 0 if everything went fine, and return a non-zero value if it didn't. So, let's say I wrote a simple main routine like so:
int main(int argc, char* argv[]) {
if (argv[1] == "true") { // not quite right, but fine for examples
return 0;
}
else if (argv[1] == "false") {
return 1;
}
}
If I run this in the commnand line as ./a.out true, then this program will return 0 and the $? variable will be set to 0 as well. If I type ./a.out false, however, the program will return 1 and $? will also be set to 1, which indicates that something went wrong.
This seems pretty redundant if you're just toying around in the command line, running commands and then echo $? to see the result, but this really becomes useful in Bash scripting, where you might want to see what the command you just ran returns. For example, the diff command returns 0 if the two files you specify don't differ, and 1 if they do. This gives a neat way to introduce some control flow into your program, but you have to be careful, because $? is set after every command you run.
I hope this helped!

Recover after "kill 0"

I have a script that invokes kill 0. I want to invoke that script from another script, and have the outer script continue to execute. (kill 0 sends a signal, defaulting to SIGTERM, to every process in the process group of the calling process; see man 2 kill.)
kill0.sh:
#!/bin/sh
kill 0
caller.sh:
#!/bin/sh
echo BEFORE
./kill0.sh
echo AFTER
The current behavior is:
$ ./caller.sh
BEFORE
Terminated
$
How can I modify caller.sh so it prints AFTER after invoking kill0.sh?
Modifying kill0.sh is not an option. Assume that kill0.sh might read from stdin and write to stdout and/or stderr before invoking kill 0, and I don't want to interfere with that. I still want the kill 0 command to kill the kill0.sh process itself; I just don't want it to kill the caller as well.
I'm using Ubuntu 16.10 x86_64, and /bin/sh is a symlink to dash. That shouldn't matter, and I prefer answers that don't depend on that.
This is of course a simplified version of a larger set of scripts, so I'm at some risk of having an XY problem, but I think that a solution to the problem as stated here should let me solve the actual problem. (I have a wrapper script that invokes a specified command, capturing and displaying its output, with some other bells and whistles.)
One solution
You need to trap the signal in the parent, but enable it in the child. So a script like run-kill0.sh could be:
#!/bin/sh
echo BEFORE
trap '' TERM
(trap 15; exec ./kill0.sh)
echo AFTER
The first trap disables the TERM signal. The second trap in the sub-shell re-enables the signal (using the signal number instead of the name — see below) before running the kill0.sh script. Using exec is a minor optimization — you can omit it and it will work the same.
Digression on obscure syntactic details
Why 15 instead of TERM in the sub-shell? Because when I tested it with TERM instead of 15, I got:
$ sh -x run-kill0.sh
+ echo BEFORE
BEFORE
+ trap '' TERM
+ trap TERM
trap: usage: trap [-lp] [arg signal_spec ...]
+ echo AFTER
AFTER
$
When I used 15 in place of TERM (twice), I got:
$ sh -x run-kill0.sh
+ echo BEFORE
BEFORE
+ trap '' 15
+ trap 15
+ exec ./kill0.sh
Terminated: 15
+ echo AFTER
AFTER
$
Using TERM in place of the first 15 would also work.
Bash documentation on trap
Studying the Bash manual for trap shows:
trap [-lp] [arg] [sigspec …]
The commands in arg are to be read and executed when the shell receives signal sigspec. If arg is absent (and there is a single sigspec) or equal to ‘-’, each specified signal’s disposition is reset to the value it had when the shell was started.
A second solution
The second sentence is the key: trap - TERM should (and empirically does) work.
#!/bin/sh
echo BEFORE
trap '' TERM
(trap - TERM; exec ./kill0.sh)
echo AFTER
Running that yields:
$ sh -x run-kill0.sh
+ echo BEFORE
BEFORE
+ trap '' TERM
+ trap - TERM
+ exec ./kill0.sh
Terminated: 15
+ echo AFTER
AFTER
$
I've just re-remembered why I use numbers and not names (but my excuse is that the shell — it wasn't Bash in those days — didn't recognize signal names when I learned it).
POSIX documentation for trap
However, in Bash's defense, the POSIX spec for trap says:
If the first operand is an unsigned decimal integer, the shell shall treat all operands as conditions, and shall reset each condition to the default value. Otherwise, if there are operands, the first is treated as an action and the remaining as conditions.
If action is '-', the shell shall reset each condition to the default value. If action is null ( "" ), the shell shall ignore each specified condition if it arises.
This is clearer than the Bash documentation, IMO. It states why trap 15 works. There's also a minor glitch in the presentation. The synopsis says (on one line):
trap n [condition...]trap [action condition...]
It should say (on two lines):
trapn[condition...]
trap [action condition...]

Listing all system exit status codes with descriptions

I know $? from shell holds the last executed programs exit status.
For example, when I run below commands, I saw different status for different situation.
test$ hello
-bash: hello: command not found
test$ echo $?
127
test$ expr 1 / 0
expr: division by zero
test$ echo $?
2
I was wondering if there is any common exit status list in system or internet where i can get all the exit status with their descriptions. I found a list here, but some codes are missing, for example status code 127.
There can be no comprehensive list, because the meaning of command exit statuses is inherently command-specific. For a given command, you can usually get information about this on the respective command's manual page and Info documents.
In the case of
test$ hello
-bash: hello: command not found
test$ echo $?
127
the exit code 127 comes from bash, because the requested command itself couldn't be found.
In the case of
test$ expr 1 / 0
expr: division by zero
test$ echo $?
2
the exit code 2 comes from expr.
Some of these commands might be standardized or at least coordinated for several commands or a group of commands (e.g. "sh-compatible shells", I could imagine), but unless a command wants to conform to one of these conventions (and there are probably multiple conflicting conventions around), the command's authors are completely free to decide what they want their exit status codes to mean.
There's one important exception: All UNIX commands should adhere to this loose rule to be good citizens and provide meaningful composability (e.g. with pipes) on the command line:
0 means 'success' or "true"/"truthy"
non-0 means (in a very broad sense) 'failure' or 'non-success' or "false"/"falsy"
As you can see, this still leaves a lot of room for interpretation, which is perfectly intended, because these meanings must be specific to the context of the individual commands. (Consider e.g. the false command, that has the very purpose to "fail", thus always returns a non-0 exit code.)
The list you found describes return codes for system calls. System calls are when a program makes a request (in)to the kernel and are not the same as command invocation, thus these return codes are not (necessarily) the same as command exit codes.
The exit status is a numeric value that is returned by a program to the calling program or shell. In C programs, this is represented by the return value of the main() function or the value you give to exit(3). The only part of the number that matters are the least significant 8 bits, which means there are only values from 0 to 255.
Code Description
0 success
1-255 failure (in general)
126 the requested command (file) can't be executed (but was found)
127 command (file) not found
128 according to ABS it's used to report an invalid argument to the exit
builtin, but I wasn't able to verify that in the source code of Bash
(see code 255)
128 + N the shell was terminated by the signal N (also used like this by
various other programs)
255 wrong argument to the exit builtin (see code 128)
The lower codes 0 to 125 are not reserved and may be used for whatever the program likes to report. A value of 0 means successful termination, a value not 0 means unsuccessful termination. This behaviour (== 0, != 0) is also what Bash reacts on in some code flow control statements like if or while.
The above excerpt taken from Exit Status section from Bash Hackers Wiki.
The list you showed is really the closest possible thing to a "standardization", but frankly it looks more legit than it actually is. As far as I am aware of, almost no one pays much attention to these guys, but instead everyone names their own exit statuses:
Execute test1.sh
#!/bin/bash
a=10 ; [ "$a" -eq 9 ] && echo "Cool!" || exit 200
Output:
:~$ test1.sh
:~$ echo $?
200

Explain Different EXIT Commands in UNIX [duplicate]

This question already has answers here:
Are there any standard exit status codes in Linux?
(11 answers)
Closed 9 years ago.
I understand that EXIT command causes the shell or program to terminate.
But what is the difference between the below:
exit 2
exit 3
exit 4
exit $?
how is exit 2 different from exit 3 and so on
This is only an exit code. 0 is for fine exit, otherwise it's the error code. $? is a shell variable storing the previous exit value (so the program which ran before your one).
The exit command takes a single value which is the value of the process (e.g. shell) return code. $? is the return code from the last command executed by the shell.
For instance, the script which exits with a return code corresponding to the first argument:
#!/bin/sh
exit $1
Would give you:
# ./script 1
# echo $?
1
# ./script 2
# echo $?
2
Note on most UNIX systems, the return code is limited to a numeric value between 0 and 255, with 0 indicates success and 1-255 providing error information (specific to each process).
From the Advanced Bash-Scripting Guide, Chapter 6: Exit and Exit Status:
The exit command terminates a script, just as in a C program. It can also return a value, which is available to the script's parent process.
So the exit command lets you assign your own exit value, which you could describe in its man page, for example.
The $? will return the exit code of the previous command. For example; You write a script that executes cat example.txt, which results exit code 1. If you then do exit $?, your script will exit with the same code as cat example.txt
More info on exit codes here: Advanced Bash-Scripting Guide Chapter 6: Exit and Exit Status
Some info on $? here: What is the $? variable in shell scripting?

How to know if a background jobs are finished in shell script? [duplicate]

This question already has answers here:
Waiting for background processes to finish before exiting script
(5 answers)
Closed 9 years ago.
How to know if a background jobs are finished in shell script?
n=0
while [ $n le 10 ]
do
dosomething &
n= `expr $n + 1`
done
how can we know all dosomething processes completed or not?
after completion i want to print echo "done"
You could use wait, like so:
n=0
while [ $n le 10 ]
do
dosomething &
done
wait
# all dosomething are finished here
If you will need to wait for just a few of them you could use wait $pid, to wait for a specific pid, which you get by executing $!, which means give me the pid of the last command.
EDIT:
I've seen that there are two questions on the matter, have a look at them:
How to wait in bash for several subprocesses to finish and return exit code !=0 when any subprocess ends with code !=0?
Waiting for background processes to finish before exiting script
the second of which seems exactly a copy of your question, I'm voting to close this.
You could use the following:
for i in {1..10}; do
command &
done; wait
It gets slightly shorter using the for loop and a range of numbers.

Resources