Medido en el worker, con el único cambio de /bin/sh en una copia por hardlinks del lab (sed/grep/awk siguen siendo busybox) y stores tirables. Control busybox: 3/3 recetas selladas. brush: 0/3. Lo que pasa: 56/57 del banco POSIX (igual que busybox), 0 rechazos sobre las 1130 fases de shell del corpus, parsea el configure de ffmpeg, funciona como argv[0]=sh y con el patrón de las cards de arje. Lo que falla: el configure corre entero pero el libtool que GENERA sale con un nivel de escapado de menos en 25 líneas, y ese fichero ya no lo parsea ningún shell. El parser de brush está bien — parsea sin quejarse el libtool del control. Mecanismo exacto no determinado: echo, sustitución de comando y el propio func_quote_for_eval de libtool dan idéntico en ambos shells aislados. Y un dato independiente del bug: 813us de arranque contra 91us de busybox (8,9x), sobre decenas de miles de shells por configure. El binario son 7,25 MB contra los 1,23 MB del busybox con sus 401 applets. De paso: brush selló con el mismo hash que traía build-state del otro hub. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
87 lines
5.1 KiB
Bash
Executable File
87 lines
5.1 KiB
Bash
Executable File
#!/bin/sh
|
|
# Banco POSIX para candidatos a /bin/sh (SDD: docs/plan-botar-busybox.md §paso 3).
|
|
# Uso: scripts/sh-banco-posix.sh <ruta-al-shell>
|
|
# 57 casos POSIX ejecutados con `$SH -c`. Baseline medido 2026-09-21: busybox sh 56/57,
|
|
# brush 0.4.0 56/57 (diverge sólo en `shift` más allá de $#: devuelve 2, POSIX/busybox 1).
|
|
# NO es una prueba de suficiencia: el banco pasa y aun así brush no construye autotools.
|
|
SH="$1"; [ -n "$SH" ] || { echo "uso: $0 <ruta-al-shell>"; exit 2; }
|
|
ok=0; ko=0; KOLIST=""
|
|
t() { # t <nombre> <esperado> <codigo>
|
|
nombre="$1"; esperado="$2"; codigo="$3"
|
|
got=$("$SH" -c "$codigo" 2>&1)
|
|
if [ "$got" = "$esperado" ]; then ok=$((ok+1))
|
|
else ko=$((ko+1)); KOLIST="$KOLIST
|
|
✗ $nombre
|
|
esperado: [$esperado]
|
|
obtenido: [$got]"
|
|
fi
|
|
}
|
|
|
|
t "echo" "hola" 'echo hola'
|
|
t "pipeline" "2" 'printf "a\nb\n" | wc -l | tr -d " "'
|
|
t "redireccion" "x" 'echo x > /tmp/_p1 && cat /tmp/_p1'
|
|
t "aqui-doc" "linea" 'cat <<EOF
|
|
linea
|
|
EOF'
|
|
t "aqui-doc-guion" "sin-tab" 'cat <<-EOF
|
|
sin-tab
|
|
EOF'
|
|
t "aqui-doc-comillado" '$NOEXPAND' 'cat <<"EOF"
|
|
$NOEXPAND
|
|
EOF'
|
|
t "sust-comando" "hola" 'x=$(echo hola); echo $x'
|
|
t "sust-backtick" "hola" 'echo `echo hola`'
|
|
t "estado-salida" "1" 'false; echo $?'
|
|
t "and-or" "b" 'false && echo a || echo b'
|
|
t "for" "1 2 3" 'r=; for i in 1 2 3; do r="$r $i"; done; echo ${r# }'
|
|
t "while-read" "a|b" 'printf "a\nb\n" | { r=; while read l; do r="$r|$l"; done; echo ${r#|}; }'
|
|
t "case" "si" 'case abc in a*) echo si;; *) echo no;; esac'
|
|
t "funcion" "5" 'f() { echo $(($1+$2)); }; f 2 3'
|
|
t "local" "fuera" 'x=fuera; f() { local x=dentro; }; f; echo $x'
|
|
t "expansion-defecto" "def" 'unset v; echo ${v:-def}'
|
|
t "expansion-asigna" "def def" 'unset v; echo ${v:=def} $v'
|
|
t "expansion-error" "0" 'unset v; ( echo ${v:?falta} ) 2>/dev/null; [ $? -ne 0 ] && echo 0'
|
|
t "expansion-largo" "3" 'v=abc; echo ${#v}'
|
|
t "quita-sufijo" "arch" 'v=arch.tar.gz; echo ${v%%.*}'
|
|
t "quita-prefijo" "gz" 'v=arch.tar.gz; echo ${v##*.}'
|
|
t "aritmetica" "7" 'echo $((3+4))'
|
|
t "aritmetica-var" "6" 'x=2; echo $((x*3))'
|
|
t "test-corchete" "si" '[ 1 -lt 2 ] && echo si'
|
|
t "test-cadena" "si" '[ "a" = "a" ] && [ -n "a" ] && echo si'
|
|
t "posicionales" "a:b:c" 'set -- a b c; IFS=:; echo "$*"'
|
|
t "todos-arroba" "a b c" 'set -- a b c; echo "$@"'
|
|
t "shift" "c" 'set -- a b c; shift 2; echo $1'
|
|
t "getopts" "v=1 f=x" 'set -- -v -f x; v=0; while getopts vf: o; do case $o in v) v=1;; f) f=$OPTARG;; esac; done; echo "v=$v f=$f"'
|
|
t "source-punto" "sourced" 'echo "echo sourced" > /tmp/_p2; . /tmp/_p2'
|
|
t "subshell-aisla" "fuera" 'x=fuera; ( x=dentro ); echo $x'
|
|
t "trap-exit" "adios" 'trap "echo adios" EXIT; true'
|
|
t "set-e-corta" "antes" 'set -e; echo antes; false; echo despues'
|
|
t "set-u" "0" 'set -u; ( echo $NODEF ) 2>/dev/null; [ $? -ne 0 ] && echo 0'
|
|
t "exec-redir" "z" 'exec 3>/tmp/_p3; echo z >&3; exec 3>&-; cat /tmp/_p3'
|
|
t "glob" "si" 'mkdir -p /tmp/_g && : > /tmp/_g/f1 && for f in /tmp/_g/f*; do [ -e "$f" ] && echo si; done'
|
|
t "glob-sin-match" "/tmp/_nada*" 'for f in /tmp/_nada*; do echo $f; done'
|
|
t "IFS-split" "a b c" 'IFS=,; set -- $(echo "a,b,c"); IFS=" "; echo "$*"'
|
|
t "comillas-preservan" "a b" 'x="a b"; echo "$x"'
|
|
t "sin-comillas-parte" "a b" 'x="a b"; echo $x'
|
|
t "escape-barra" 'a\b' 'printf "%s\n" "a\\b"'
|
|
t "printf-formato" "007" 'printf "%03d\n" 7'
|
|
t "read-var" "dato" 'echo dato | { read v; echo $v; }'
|
|
t "eval" "ev" 'c="echo ev"; eval $c'
|
|
t "dollar-dollar" "si" '[ -n "$$" ] && echo si'
|
|
t "PATH-busca" "si" 'command -v echo >/dev/null && echo si'
|
|
t "anidado-sust" "ab" 'echo "$(echo a)$(echo b)"'
|
|
t "multi-cmd-punto-coma" "a b" 'echo -n "a "; echo b'
|
|
t "negacion" "si" 'if ! false; then echo si; fi'
|
|
t "bucle-until" "3" 'i=0; until [ $i -ge 3 ]; do i=$((i+1)); done; echo $i'
|
|
t "break-continue" "1 3" 'r=; for i in 1 2 3 4; do [ $i = 2 ] && continue; [ $i = 4 ] && break; r="$r $i"; done; echo ${r# }'
|
|
t "return-funcion" "7" 'f() { return 7; }; f; echo $?'
|
|
t "here-string-noposix" "SKIP" 'echo SKIP'
|
|
t "wait-bg" "si" '(sleep 0.05) & wait; echo si'
|
|
t "unset-func" "si" 'f() { echo no; }; unset -f f; command -v f >/dev/null || echo si'
|
|
t "export-hijo" "val" 'export V=val; "'"$SH"'" -c "echo \$V"'
|
|
t "shift-sin-args" "1" 'set --; shift 2>/dev/null; echo $?'
|
|
|
|
echo "$SH: OK=$ok FALLO=$ko"
|
|
[ -n "$KOLIST" ] && echo "$KOLIST"
|
|
exit $ko
|