Exit Status, Arguments, Environment#

The Shell: A Program Like Any Other Program#

  • The shell is a program just like any other program (/bin/bash)

  • Main purpose: start other programs, and report on their exit status

$ grep jfasch /etc/passwd
jfasch:x:1000:1000:Joerg Faschingbauer:/home/jfasch:/bin/bash
  • Search program grep along $PATH

  • Start it, passing it two arguments: jfasch, /etc/passwd

  • Wait for it to terminate

  • Examine its exit status

$ echo $?            # <--- $? ... exit status of last foreground process (huh?)
0

The Shell: A Programming Language#

$ if grep jfasch /etc/passwd; then echo YAY; else echo NOPE; fi
jfasch:x:1000:1000:Joerg Faschingbauer:/home/jfasch:/bin/bash
YAY
  • Exit status used as conditional for if (and while)

  • Functions, recursion, and whatnot

  • ⟶ Full programming language

  • … albeit a little weird

Exit Status#

  • An integer in the range 0-255

  • In the simplest case, a return from the program’s main function is its exit status

  • Otherwise (exiting deeper in a process’s call chain), see man -s 3 exit

Exit Status: 0 is “OK”#

#include <stdlib.h>

int main(void)
{
    exit(0);                                           // <-- 0 is "OK" 
    // return 0;                                       // <-- return from main == same
}
  • In the sunny case, an exit status of zero is returned.

  • The truth value of zero is true, paradoxically. This makes sense though: there is only one sunny case, but many opportunities to get into trouble.

$ ./exit-ok
$ echo $?
0
  • Or, programmatically …

$ if ./exit-ok; then echo YAY; else echo NOPE; fi
YAY

Exit Status: != 0 is “Not OK”#

#include <stdlib.h>

int main(void)
{
    exit(42);                                          // <-- != 0 is "Not OK"
}
  • In any error case, an exit status of non-zero is returned.

  • The truth value of non-zero is false. Again, this makes sense because there are possibly many things why a program might fail.

$ ./exit-nok
$ echo $?
42
  • Or, programmatically …

$ if ./exit-nok; then echo YAY; else echo NOPE; fi
NOPE

Argument Vector (int argc, char** argv)#

  • Passing parameters to programs

  • argc: number of arguments

  • argv: string array - the “argument vector”

  • argv[0]: how the command was invoked (unused, mostly)

../../../../../../../_images/argv.svg
#include <print>

int main(int argc, char** argv)
{
    std::println("argc: {}", argc);
    for (int i=0; i<argc; i++)
        std::println("argv[{}]: {}", i, argv[i]);

    return 0;
}
$ ./argv
argc: 1
argv[0]: ./argv
$ ./argv hello sweetheart
argc: 3
argv[0]: ./argv
argv[1]: hello
argv[2]: sweetheart

Environment Variables#

  • Environment variables are a process attribute (not related to any programming language)

  • Inherited to child processes

  • A process can use getenv() (here) to read its value

../../../../../../../_images/environ-inherit.svg
#include <stdlib.h>
#include <print>

int main(int argc, char** argv)
{
    const char* foo_value = getenv("FOO");
    if (foo_value != nullptr)
        std::println("FOO={}", foo_value);
    else
        std::println("FOO is not set");

    return 0;
}
$ ./sysprog-process-environ
FOO is not set
$ export FOO=bar
$ ./sysprog-process-environ
FOO=bar