#!/bin/bash # # Usage: # ./count-procs.sh set -o nounset set -o pipefail set -o errexit proc count-procs { var sh = $1 var code = $2 # Hm I didn't know -e is like a mini-language. '-e open' is thes same as '-e # trace=open'. signal=none turns off the SIGCHLD lines. # # NOTE we grep for [pid and rely on the code itself to echo [pid-of-sh $$]. code := "'echo "[pid-of-sh $$]";'" $code"" strace -e 'trace=fork,execve' -e 'signal=none' -e 'verbose=none' -ff -- \ $sh -c $code !2 > !1 | fgrep '[pid' || true } proc test-many { for code in [@Argv] { echo echo echo "--- $code ---" echo for sh in [dash bash mksh zsh] { echo echo echo "--- $sh ---" echo count-procs $sh $code } } } proc t1 { test-many \ 'echo hi' \ '/bin/echo one; /bin/echo two' \ '{ /bin/echo one; /bin/echo two; }' \ '{ echo one; echo two; } | wc -l' \ '( echo one; echo two ) | wc -l' } @Argv (CommandList children: [ (C {(set)} {(-o)} {(nounset)}) (C {(set)} {(-o)} {(pipefail)}) (C {(set)} {(-o)} {(errexit)}) (FuncDef name: count-procs body: (BraceGroup children: [ (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:sh) op: Equal rhs: {($ VSub_Number "$1")} spids: [41] ) ] spids: [39] ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:code) op: Equal rhs: {($ VSub_Number "$2")} spids: [47] ) ] spids: [45] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:code) op: Equal rhs: {(SQ <"echo \"[pid-of-sh $$]\";">) (DQ (" ") ($ VSub_Name "$code"))} spids: [69] ) ] spids: [69] ) (AndOr children: [ (Pipeline children: [ (SimpleCommand words: [ {(strace)} {(-e)} {(SQ <"trace=fork,execve">)} {(-e)} {(SQ <"signal=none">)} {(-e)} {(SQ <"verbose=none">)} {(-ff)} {(--)} {($ VSub_Name "$sh")} {(-c)} {(DQ ($ VSub_Name "$code"))} ] redirects: [(Redir op_id:Redir_GreatAnd fd:2 arg_word:{(1)} spids:[113])] ) (C {(fgrep)} {(SQ <"[pid">)}) ] negated: False ) (C {(true)}) ] op_id: Op_DPipe ) ] spids: [36] ) spids: [32 35] ) (FuncDef name: test-many body: (BraceGroup children: [ (ForEach iter_name: code iter_words: [{(DQ ($ VSub_At "$@"))}] do_arg_iter: False body: (DoGroup children: [ (C {(echo)}) (C {(echo)}) (C {(echo)} {(DQ ("--- ") ($ VSub_Name "$code") (" ---"))}) (C {(echo)}) (ForEach iter_name: sh iter_words: [{(dash)} {(bash)} {(mksh)} {(zsh)}] do_arg_iter: False body: (DoGroup children: [ (C {(echo)}) (C {(echo)}) (C {(echo)} {(DQ ("--- ") ($ VSub_Name "$sh") (" ---"))}) (C {(echo)}) (C {(count-procs)} {($ VSub_Name "$sh")} {(DQ ($ VSub_Name "$code"))}) ] spids: [186 216] ) spids: [176 184] ) ] spids: [149 219] ) spids: [143 147] ) ] spids: [135] ) spids: [131 134] ) (FuncDef name: t1 body: (BraceGroup children: [ (C {(test-many)} {(SQ <"echo hi">)} {(SQ <"/bin/echo one; /bin/echo two">)} {(SQ <"{ /bin/echo one; /bin/echo two; }">)} {(SQ <"{ echo one; echo two; } | wc -l">)} {(SQ <"( echo one; echo two ) | wc -l">)} ) ] spids: [228] ) spids: [224 227] ) (C {(DQ ($ VSub_At "$@"))}) ] )