1 #!/usr/bin/env bash
2 #
3 # NOTE:
4 # - $! is tested in background.test.sh
5 # - $- is tested in sh-options
6 #
7 # TODO: It would be nice to make a table, like:
8 #
9 # $$ $BASHPID $PPID $SHLVL $BASH_SUBSHELL
10 # X
11 # (Subshell, Command Sub, Pipeline, Spawn $0)
12 #
13 # And see whether the variable changed.
14
15 ### $PWD
16 # Just test that it has a slash for now.
17 echo $PWD | grep -o /
18 # status: 0
19
20 ### $1 .. $9 are scoped, while $0 is not
21 func() { echo $0 $1 $2 | sed -e 's/.*sh/sh/'; }
22 func a b
23 # stdout: sh a b
24
25 ### $?
26 echo $? # starts out as 0
27 sh -c 'exit 33'
28 echo $?
29 # stdout-json: "0\n33\n"
30 # status: 0
31
32 ### $#
33 set -- 1 2 3 4
34 echo $#
35 # stdout: 4
36 # status: 0
37
38 ### $_
39 # This is bash-specific.
40 echo hi
41 echo $_
42 # stdout-json: "hi\nhi\n"
43 # N-I dash/mksh stdout-json: "hi\n\n"
44
45 ### $$ looks like a PID
46 # Just test that it has decimal digits
47 echo $$ | egrep '[0-9]+'
48 # status: 0
49
50 ### $$ doesn't change with subshell or command sub
51 # Just test that it has decimal digits
52 set -o errexit
53 die() {
54 echo 1>&2 "$@"; exit 1
55 }
56 parent=$$
57 test -n "$parent" || die "empty PID in parent"
58 ( child=$$
59 test -n "$child" || die "empty PID in subshell"
60 test "$parent" = "$child" || die "should be equal: $parent != $child"
61 echo 'subshell OK'
62 )
63 echo $( child=$$
64 test -n "$child" || die "empty PID in command sub"
65 test "$parent" = "$child" || die "should be equal: $parent != $child"
66 echo 'command sub OK'
67 )
68 exit 3 # make sure we got here
69 # status: 3
70 ## STDOUT:
71 subshell OK
72 command sub OK
73 ## END
74
75 ### $BASHPID DOES change with subshell and command sub
76 set -o errexit
77 die() {
78 echo 1>&2 "$@"; exit 1
79 }
80 parent=$BASHPID
81 test -n "$parent" || die "empty BASHPID in parent"
82 ( child=$BASHPID
83 test -n "$child" || die "empty BASHPID in subshell"
84 test "$parent" != "$child" || die "should not be equal: $parent = $child"
85 echo 'subshell OK'
86 )
87 echo $( child=$BASHPID
88 test -n "$child" || die "empty BASHPID in command sub"
89 test "$parent" != "$child" ||
90 die "should not be equal: $parent = $child"
91 echo 'command sub OK'
92 )
93 exit 3 # make sure we got here
94 ## status: 3
95 ## STDOUT:
96 subshell OK
97 command sub OK
98 ## END
99 ## N-I dash status: 1
100 ## N-I dash stdout-json: ""
101
102 ### Background PID $! looks like a PID
103 sleep 0.01 &
104 pid=$!
105 wait
106 echo $pid | egrep '[0-9]+' >/dev/null
107 echo status=$?
108 # stdout: status=0
109
110 ### $PPID
111 echo $PPID | egrep '[0-9]+'
112 # status: 0
113
114 # NOTE: There is also $BASHPID
115
116 ### $PIPESTATUS
117 echo hi | sh -c 'cat; exit 33' | wc -l >/dev/null
118 argv.py "${PIPESTATUS[@]}"
119 # status: 0
120 # stdout: ['0', '33', '0']
121 # N-I dash stdout-json: ""
122 # N-I dash status: 2
123
124 ### $RANDOM
125 expr $0 : '.*/osh$' && exit 99 # Disabled because of spec-runner.sh issue
126 echo $RANDOM | egrep '[0-9]+'
127 # status: 0
128 # N-I dash status: 1
129
130 ### $UID and $EUID
131 # These are both bash-specific.
132 set -o errexit
133 echo $UID | egrep -o '[0-9]+' >/dev/null
134 echo $EUID | egrep -o '[0-9]+' >/dev/null
135 echo status=$?
136 # stdout: status=0
137 # N-I dash/mksh stdout-json: ""
138 # N-I dash/mksh status: 1