OILS / demo / xtrace1.sh View on Github | oilshell.org

371 lines, 206 significant
1#!/usr/bin/env bash
2#
3# Usage:
4# demo/xtrace1.sh <function name>
5
6#set -o nounset
7#set -o pipefail
8#set -o errexit
9
10myfunc() {
11 : "myfunc $1"
12}
13
14banner() {
15 echo
16 echo "$@"
17 echo
18}
19
20# bash is the only shell with the "first char repeated" behavior
21first_char() {
22 for sh in bash dash mksh zsh bin/osh; do
23 echo
24 echo $sh
25 export PS4='$PWD '
26 #export PS4='$ '
27 $sh -x -c 'echo $(echo hi)-'
28 done
29}
30
31# bash repeats the + for command sub, eval, source. Other shells don't.
32posix() {
33 banner COMMANDSUB
34 set -x
35 foo=$(myfunc commandsub)
36 set +x
37
38 # Hm this gives you ++
39 banner EVAL
40 set -x
41 eval myfunc evalarg
42 set +x
43
44 # Also gives you ++
45 banner SOURCE
46 set -x
47 . spec/testdata/source-argv.sh 1 2
48 set +x
49}
50
51# Various stacks:
52# - proc call stack (similar: FUNCNAME)
53# - process stack (similar: BASHPID)
54# - interpreter stack (eval, source. xtrace already respects this)
55# - and maybe Oil subinterpreters
56
57# User level:
58# - Color
59# - Indentation
60# - HTML
61#
62# What you really want PARSEABLE traces. Which means each trace item is ONE
63# LINE. And emitted by a single write() call.
64#
65# Related debugging features of OSH:
66#
67# - pp cell (ASDL), pp proc (QTT)
68# - osh -n (ASDL)
69# - Oil expressions: = keyword (ASDL)
70
71shopt -s expand_aliases
72alias e=echo
73
74simple() {
75 e alias
76 myfunc invoke
77 ( myfunc subshell )
78}
79
80main() {
81 banner ALIAS
82
83 set -x
84 e alias
85 set +x
86
87 banner FUNC
88
89 set -x
90 myfunc invoke
91 set +x
92
93 banner SUBSHELL
94 # No increase in +
95 # pid and SHLVL do NOT increase. BASHPID increases.
96 set -x
97 : pid=$$ BASHPID=$BASHPID SHLVL=$SHLVL
98 ( myfunc subshell; : pid=$$ BASHPID=$BASHPID SHLVL=$SHLVL )
99 set +x
100
101 # Now it changes to ++
102 banner COMMANDSUB
103 set -x
104 foo=$(myfunc commandsub)
105 set +x
106
107 banner PIPELINE
108 set -x
109 myfunc pipeline | sort
110 set +x
111
112 banner THREE
113
114 # Increase to three
115 set -x
116 foo=$(echo $(myfunc commandsub))
117 echo $foo
118 set +x
119
120 # Hm this gives you ++
121 banner EVAL
122 set -x
123 eval myfunc evalarg
124 set +x
125
126 # Also gives you ++
127 banner SOURCE
128 set -x
129 source spec/testdata/source-argv.sh 1 2
130 set +x
131
132 banner RECURSIVE
133 set -x
134 $0 myfunc dollar-zero
135 set +x
136
137 # TODO: SHELLOPTS not set here?
138 banner "SHELLOPTS=$SHELLOPTS"
139
140 export SHELLOPTS
141 set -x
142 $0 myfunc dollar-zero-shellopts
143 set +x
144}
145
146main2() {
147 set -x
148
149 # OK this is useful.
150
151 # https://unix.stackexchange.com/questions/355965/how-to-check-which-line-of-a-bash-script-is-being-executed
152 PS4='+${LINENO}: '
153
154 # Test runtime errors like this
155 #PS4='+${LINENO}: $(( 1 / 0 ))'
156
157 myfunc ps4
158 foo=$(myfunc ps4-commandsub)
159 echo foo
160}
161
162slowfunc() {
163 for i in "$@"; do
164 sleep 0.$i
165 done
166}
167
168concurrency() {
169 set -x
170
171 # PID prefix would be nice here
172 slowfunc 1 3 | slowfunc 2 4 5 | slowfunc 6
173}
174
175task() {
176 for i in "$@"; do
177 echo $i
178 sleep 0.$i
179 done
180}
181
182through_xargs() {
183 set -x
184 export PS4='+ $$ '
185
186 # This doesn't work because xargs invokes $0! Not OSH.
187 export OILS_HIJACK_SHEBANG=1
188
189 # This makes us trace through xargs.
190 #
191 # problem: $0 invokes bash because of the shebang.
192 # We can't use $SHELL $0.
193 # - bash is the only shell that sets $SHELL.
194 # - It's not the right value. "If it is not set when the shell starts, bash
195 # assigns to it the full pathname of the current user's login shell."
196
197 export SHELLOPTS
198 seq 6 | xargs -n 2 -P 3 -- $0 task
199}
200
201my_ps4() {
202 for i in {1..3}; do
203 echo -n $i
204 done
205}
206
207# The problem with this is you don't want to fork the shell for every line!
208
209call_func_in_ps4() {
210 set -x
211 PS4='[$(my-ps4)] '
212 echo one
213 echo two
214}
215
216# EXPANDED argv is displayed, NOT the raw input.
217# - OK just do assignments?
218
219# - bash shows the 'for x in 1 2 3' all on one line
220# - dash doesn't show the 'for'
221# - neither does zsh and mksh
222# - zsh shows line numbers and the function name!
223
224# - two statements on one line are broken up
225
226# - bash doesn't show 'while'
227
228# The $((i+1)) is evaluated. Hm.
229
230# Hm we don't implement this, only works at top level
231# set -v
232
233loop() {
234 set -x
235
236 for x in 1 \
237 2 \
238 3; do
239 echo $x; echo =$(echo {x}-)
240 done
241
242 i=0
243 while test $i -lt 3; do
244 echo $x; echo ${x}-
245 i=$((i+1))
246 if true; then continue; fi
247 done
248}
249
250atoms1() {
251 set -x
252
253 foo=bar
254
255 # This messes up a lot of printing.
256 x='one
257 two'
258
259 i=1
260
261 [[ -n $x ]]; echo "$x"
262
263 # $i gets expanded, not i
264 (( y = 42 + i + $i )); echo yo
265
266 [[ -n $x
267 ]]
268
269 (( y =
270 42 +
271 i +
272 $i
273 ))
274}
275
276atoms2() {
277 set -x
278
279 x='one
280 two'
281
282 declare -a a
283 a[1]="$x"
284
285 # This works
286 declare -A A
287 A["$x"]=1
288
289 a=(1 2 3)
290 A=([k]=v)
291
292 a=("$x" $x)
293 A=([k]="$x")
294
295 # Assignment builtins
296
297 declare -g -r d=0 foo=bar
298 typeset t=1
299 local lo=2
300 export e=3 f=foo
301 readonly r=4
302}
303
304compound() {
305 set -x
306
307 # Nothing for time
308 time sleep 0
309
310 # There is no tracing for () and {}
311 { echo b1
312 echo b2
313 }
314
315 ( echo c1
316 echo c2
317 )
318
319 # no tracing for if; just the conditions
320 if test -d /; then
321 echo yes
322 else
323 echo no
324 fi
325
326 # Hm this causes a concurrency problem.
327 # I think we want to buffer the line
328 ls | wc -l | sort
329
330 # There IS tracing for 'case' line
331 case foo in
332 fo*)
333 echo case
334 ;;
335 *)
336 echo default
337 ;;
338 esac
339
340 f() {
341 echo hi
342 }
343
344}
345
346oil_constructs() {
347 echo TODO
348 # BareDecl, VarDecl, PlaceMutation, Expr
349}
350
351details() {
352 PS4='+ ${BASH_SOURCE[0]}:${FUNCNAME[0]}:${LINENO} '
353
354 # X_pid can have a space after it, or call it ${X_tag}
355 # Or should we could call the whole thing ? ${XTRACE_PREFIX} ?
356 # Idea: $PS5 and $PS6 for push and pop?
357
358 # Problem: remove the first char behavior? Or only respect it in PS4.
359 #
360 # This string can be OIL_XTRACE_PREFIX='' or something.
361 PS4=' ${X_indent}${X_punct}${X_tag}${BASH_SOURCE[0]}:${FUNCNAME[0]}:${LINENO} '
362
363
364 set -x
365
366 echo hi
367 echo command=$(echo inner)
368 eval 'echo eval'
369}
370
371"$@"