| 1 | # xtrace test.  Test PS4 and line numbers, etc.
 | 
| 2 | 
 | 
| 3 | ## oils_failures_allowed: 1
 | 
| 4 | ## compare_shells: bash dash mksh
 | 
| 5 | 
 | 
| 6 | #### unset PS4
 | 
| 7 | set -x
 | 
| 8 | echo 1
 | 
| 9 | unset PS4
 | 
| 10 | echo 2
 | 
| 11 | ## STDOUT:
 | 
| 12 | 1
 | 
| 13 | 2
 | 
| 14 | ## STDERR:
 | 
| 15 | + echo 1
 | 
| 16 | + unset PS4
 | 
| 17 | echo 2
 | 
| 18 | ## END
 | 
| 19 | 
 | 
| 20 | #### set -o verbose prints unevaluated code
 | 
| 21 | set -o verbose
 | 
| 22 | x=foo
 | 
| 23 | y=bar
 | 
| 24 | echo $x
 | 
| 25 | echo $(echo $y)
 | 
| 26 | ## STDOUT:
 | 
| 27 | foo
 | 
| 28 | bar
 | 
| 29 | ## STDERR:
 | 
| 30 | x=foo
 | 
| 31 | y=bar
 | 
| 32 | echo $x
 | 
| 33 | echo $(echo $y)
 | 
| 34 | ## OK bash STDERR:
 | 
| 35 | x=foo
 | 
| 36 | y=bar
 | 
| 37 | echo $x
 | 
| 38 | echo $(echo $y)
 | 
| 39 | ## END
 | 
| 40 | 
 | 
| 41 | #### xtrace with unprintable chars
 | 
| 42 | case $SH in (dash) exit ;; esac
 | 
| 43 | 
 | 
| 44 | s=$'a\x03b\004c\x00d'
 | 
| 45 | set -o xtrace
 | 
| 46 | echo "$s"
 | 
| 47 | ## stdout-repr: 'a\x03b\x04c\x00d\n'
 | 
| 48 | ## STDERR:
 | 
| 49 | + echo $'a\u0003b\u0004c\u0000d'
 | 
| 50 | ## END
 | 
| 51 | ## OK bash stdout-repr: 'a\x03b\x04c\n'
 | 
| 52 | ## OK bash stderr-repr: "+ echo $'a\\003b\\004c'\n"
 | 
| 53 | 
 | 
| 54 | # nonsensical output?
 | 
| 55 | ## BUG mksh stdout-repr: 'a;\x04c\r\n'
 | 
| 56 | ## BUG mksh stderr-repr: "+ echo $'a;\\004c\\r'\n"
 | 
| 57 | ## N-I dash stdout-json: ""
 | 
| 58 | ## N-I dash stderr-json: ""
 | 
| 59 | 
 | 
| 60 | #### xtrace with unicode chars
 | 
| 61 | case $SH in (dash) exit ;; esac
 | 
| 62 | 
 | 
| 63 | mu1='[μ]'
 | 
| 64 | mu2=$'[\u03bc]'
 | 
| 65 | 
 | 
| 66 | set -o xtrace
 | 
| 67 | echo "$mu1" "$mu2"
 | 
| 68 | 
 | 
| 69 | ## STDOUT:
 | 
| 70 | [μ] [μ]
 | 
| 71 | ## END
 | 
| 72 | ## STDERR:
 | 
| 73 | + echo '[μ]' '[μ]'
 | 
| 74 | ## END
 | 
| 75 | ## N-I dash stdout-json: ""
 | 
| 76 | ## N-I dash stderr-json: ""
 | 
| 77 | 
 | 
| 78 | #### xtrace with paths
 | 
| 79 | set -o xtrace
 | 
| 80 | echo my-dir/my_file.cc
 | 
| 81 | ## STDOUT:
 | 
| 82 | my-dir/my_file.cc
 | 
| 83 | ## END
 | 
| 84 | ## STDERR:
 | 
| 85 | + echo my-dir/my_file.cc
 | 
| 86 | ## END
 | 
| 87 | 
 | 
| 88 | #### xtrace with tabs
 | 
| 89 | case $SH in (dash) exit ;; esac
 | 
| 90 | 
 | 
| 91 | set -o xtrace
 | 
| 92 | echo $'[\t]'
 | 
| 93 | ## stdout-json: "[\t]\n"
 | 
| 94 | ## STDERR:
 | 
| 95 | + echo $'[\t]'
 | 
| 96 | ## END
 | 
| 97 | # this is a bug because it's hard to see
 | 
| 98 | ## BUG bash stderr-json: "+ echo '[\t]'\n"
 | 
| 99 | ## N-I dash stdout-json: ""
 | 
| 100 | ## N-I dash stderr-json: ""
 | 
| 101 | 
 | 
| 102 | #### xtrace with whitespace, quotes, and backslash
 | 
| 103 | set -o xtrace
 | 
| 104 | echo '1 2' \' \" \\
 | 
| 105 | ## STDOUT:
 | 
| 106 | 1 2 ' " \
 | 
| 107 | ## END
 | 
| 108 | 
 | 
| 109 | # YSH is different because backslashes require $'\\' and not '\', but that's OK
 | 
| 110 | ## STDERR:
 | 
| 111 | + echo '1 2' $'\'' '"' $'\\'
 | 
| 112 | ## END
 | 
| 113 | 
 | 
| 114 | ## OK bash/mksh STDERR:
 | 
| 115 | + echo '1 2' \' '"' '\'
 | 
| 116 | ## END
 | 
| 117 | 
 | 
| 118 | ## BUG dash STDERR:
 | 
| 119 | + echo 1 2 ' " \
 | 
| 120 | ## END
 | 
| 121 | 
 | 
| 122 | #### xtrace with newlines
 | 
| 123 | # bash and dash trace this badly.  They print literal newlines, which I don't
 | 
| 124 | # want.
 | 
| 125 | set -x
 | 
| 126 | echo $'[\n]'
 | 
| 127 | ## STDOUT:
 | 
| 128 | [
 | 
| 129 | ]
 | 
| 130 | ## STDERR: 
 | 
| 131 | + echo $'[\n]'
 | 
| 132 | ## END
 | 
| 133 | # bash has ugly output that spans lines
 | 
| 134 | ## OK bash STDERR:
 | 
| 135 | + echo '[
 | 
| 136 | ]'
 | 
| 137 | ## END
 | 
| 138 | ## N-I dash stdout-json: "$[\n]\n"
 | 
| 139 | ## N-I dash stderr-json: "+ echo $[\\n]\n"
 | 
| 140 | 
 | 
| 141 | #### xtrace written before command executes
 | 
| 142 | set -x
 | 
| 143 | echo one >&2
 | 
| 144 | echo two >&2
 | 
| 145 | ## stdout-json: ""
 | 
| 146 | ## STDERR:
 | 
| 147 | + echo one
 | 
| 148 | one
 | 
| 149 | + echo two
 | 
| 150 | two
 | 
| 151 | ## OK mksh STDERR:
 | 
| 152 | # mksh traces redirects!
 | 
| 153 | + >&2 
 | 
| 154 | + echo one
 | 
| 155 | one
 | 
| 156 | + >&2 
 | 
| 157 | + echo two
 | 
| 158 | two
 | 
| 159 | ## END
 | 
| 160 | 
 | 
| 161 | #### Assignments and assign builtins
 | 
| 162 | set -x
 | 
| 163 | x=1 x=2; echo $x; readonly x=3
 | 
| 164 | ## STDOUT:
 | 
| 165 | 2
 | 
| 166 | ## END
 | 
| 167 | ## STDERR:
 | 
| 168 | + x=1
 | 
| 169 | + x=2
 | 
| 170 | + echo 2
 | 
| 171 | + readonly x=3
 | 
| 172 | ## END
 | 
| 173 | ## OK dash STDERR:
 | 
| 174 | + x=1 x=2
 | 
| 175 | + echo 2
 | 
| 176 | + readonly x=3
 | 
| 177 | ## END
 | 
| 178 | ## OK dash STDERR:
 | 
| 179 | + x=1 x=2
 | 
| 180 | + echo 2
 | 
| 181 | + readonly x=3
 | 
| 182 | ## END
 | 
| 183 | ## OK bash STDERR:
 | 
| 184 | + x=1
 | 
| 185 | + x=2
 | 
| 186 | + echo 2
 | 
| 187 | + readonly x=3
 | 
| 188 | + x=3
 | 
| 189 | ## END
 | 
| 190 | ## OK mksh STDERR:
 | 
| 191 | + x=1 x=2 
 | 
| 192 | + echo 2
 | 
| 193 | + readonly 'x=3'
 | 
| 194 | ## END
 | 
| 195 | 
 | 
| 196 | #### [[ ]]
 | 
| 197 | case $SH in (dash|mksh) exit ;; esac
 | 
| 198 | 
 | 
| 199 | set -x
 | 
| 200 | 
 | 
| 201 | dir=/
 | 
| 202 | if [[ -d $dir ]]; then
 | 
| 203 |   (( a = 42 ))
 | 
| 204 | fi
 | 
| 205 | ## stdout-json: ""
 | 
| 206 | ## STDERR:
 | 
| 207 | + dir=/
 | 
| 208 | + [[ -d $dir ]]
 | 
| 209 | + (( a = 42 ))
 | 
| 210 | ## END
 | 
| 211 | ## OK bash STDERR:
 | 
| 212 | + dir=/
 | 
| 213 | + [[ -d / ]]
 | 
| 214 | + ((  a = 42  ))
 | 
| 215 | ## END
 | 
| 216 | ## N-I dash/mksh stderr-json: ""
 | 
| 217 | 
 | 
| 218 | #### PS4 is scoped
 | 
| 219 | set -x
 | 
| 220 | echo one
 | 
| 221 | f() { 
 | 
| 222 |   local PS4='- '
 | 
| 223 |   echo func;
 | 
| 224 | }
 | 
| 225 | f
 | 
| 226 | echo two
 | 
| 227 | ## STDERR:
 | 
| 228 | + echo one
 | 
| 229 | + f
 | 
| 230 | + local 'PS4=- '
 | 
| 231 | - echo func
 | 
| 232 | + echo two
 | 
| 233 | ## END
 | 
| 234 | ## OK osh STDERR:
 | 
| 235 | + echo one
 | 
| 236 | + f
 | 
| 237 | + local PS4='- '
 | 
| 238 | - echo func
 | 
| 239 | + echo two
 | 
| 240 | ## END
 | 
| 241 | ## OK dash STDERR:
 | 
| 242 | # dash loses information about spaces!  There is a trailing space, but you
 | 
| 243 | # can't see it.
 | 
| 244 | + echo one
 | 
| 245 | + f
 | 
| 246 | + local PS4=- 
 | 
| 247 | - echo func
 | 
| 248 | + echo two
 | 
| 249 | ## END
 | 
| 250 | ## OK mksh STDERR:
 | 
| 251 | # local gets turned into typeset
 | 
| 252 | + echo one
 | 
| 253 | + f
 | 
| 254 | + typeset 'PS4=- '
 | 
| 255 | - echo func
 | 
| 256 | + echo two
 | 
| 257 | ## END
 | 
| 258 | 
 | 
| 259 | #### xtrace with variables in PS4
 | 
| 260 | PS4='+$x:'
 | 
| 261 | set -o xtrace
 | 
| 262 | x=1
 | 
| 263 | echo one
 | 
| 264 | x=2
 | 
| 265 | echo two
 | 
| 266 | ## STDOUT:
 | 
| 267 | one
 | 
| 268 | two
 | 
| 269 | ## END
 | 
| 270 | 
 | 
| 271 | ## STDERR:
 | 
| 272 | +:x=1
 | 
| 273 | +1:echo one
 | 
| 274 | +1:x=2
 | 
| 275 | +2:echo two
 | 
| 276 | ## END
 | 
| 277 | 
 | 
| 278 | ## OK mksh STDERR:
 | 
| 279 | # mksh has trailing spaces
 | 
| 280 | +:x=1 
 | 
| 281 | +1:echo one
 | 
| 282 | +1:x=2 
 | 
| 283 | +2:echo two
 | 
| 284 | ## END
 | 
| 285 | 
 | 
| 286 | ## OK osh/dash STDERR:
 | 
| 287 | # the PS4 string is evaluated AFTER the variable is set.  That's OK
 | 
| 288 | +1:x=1
 | 
| 289 | +1:echo one
 | 
| 290 | +2:x=2
 | 
| 291 | +2:echo two
 | 
| 292 | ## END
 | 
| 293 | 
 | 
| 294 | #### PS4 with unterminated ${
 | 
| 295 | # osh shows inline error; maybe fail like dash/mksh?
 | 
| 296 | x=1
 | 
| 297 | PS4='+${x'
 | 
| 298 | set -o xtrace
 | 
| 299 | echo one
 | 
| 300 | echo status=$?
 | 
| 301 | ## STDOUT:
 | 
| 302 | one
 | 
| 303 | status=0
 | 
| 304 | ## END
 | 
| 305 | # mksh and dash both fail.  bash prints errors to stderr.
 | 
| 306 | ## OK dash stdout-json: ""
 | 
| 307 | ## OK dash status: 2
 | 
| 308 | ## OK mksh stdout-json: ""
 | 
| 309 | ## OK mksh status: 1
 | 
| 310 | 
 | 
| 311 | #### PS4 with unterminated $(
 | 
| 312 | # osh shows inline error; maybe fail like dash/mksh?
 | 
| 313 | x=1
 | 
| 314 | PS4='+$(x'
 | 
| 315 | set -o xtrace
 | 
| 316 | echo one
 | 
| 317 | echo status=$?
 | 
| 318 | ## STDOUT:
 | 
| 319 | one
 | 
| 320 | status=0
 | 
| 321 | ## END
 | 
| 322 | # mksh and dash both fail.  bash prints errors to stderr.
 | 
| 323 | ## OK dash stdout-json: ""
 | 
| 324 | ## OK dash status: 2
 | 
| 325 | ## OK mksh stdout-json: ""
 | 
| 326 | ## OK mksh status: 1
 | 
| 327 | 
 | 
| 328 | #### PS4 with runtime error
 | 
| 329 | # osh shows inline error; maybe fail like dash/mksh?
 | 
| 330 | x=1
 | 
| 331 | PS4='+oops $(( 1 / 0 )) \$'
 | 
| 332 | set -o xtrace
 | 
| 333 | echo one
 | 
| 334 | echo status=$?
 | 
| 335 | ## STDOUT:
 | 
| 336 | one
 | 
| 337 | status=0
 | 
| 338 | ## END
 | 
| 339 | # mksh and dash both fail.  bash prints errors to stderr.
 | 
| 340 | ## OK dash stdout-json: ""
 | 
| 341 | ## OK dash status: 2
 | 
| 342 | ## OK mksh stdout-json: ""
 | 
| 343 | ## OK mksh status: 1
 | 
| 344 | 
 | 
| 345 | 
 | 
| 346 | #### Reading $? in PS4
 | 
| 347 | PS4='[last=$?] '
 | 
| 348 | set -x
 | 
| 349 | false
 | 
| 350 | echo ok
 | 
| 351 | ## STDOUT:
 | 
| 352 | ok
 | 
| 353 | ## END
 | 
| 354 | ## STDERR:
 | 
| 355 | [last=0] false
 | 
| 356 | [last=1] echo ok
 | 
| 357 | ## END
 | 
| 358 | ## OK osh STDERR:
 | 
| 359 | [last=0] 'false'
 | 
| 360 | [last=1] echo ok
 | 
| 361 | ## END
 |