Repository navigation
fix(interpreter): extglob, nocasematch, globstar, substrings and $'...' quoting like bash - #2632
Merged
Merged
Conversation
[[ == ]] always matches with extglob (bash 5.2). shopt nocasematch folds
case for case, [[ ==/=~ ]] and ${v/pat/rep}. !(..) may consume an empty
prefix; escaped | and quotes inside a group stay literal; an unbalanced
group is literal. Extglob matching now spends a shared step budget
(TM-DOS-031).
${s:off:-n} counts back from the end, an offset before the start or past
the end selects nothing, a negative array/positional length is bash's
'substring expression < 0' line abort, and ${#@}/${#*} count the
positional parameters.
Each invalid name is reported and skipped; the valid names in the same call still take effect. shopt -s/-u with -o keeps status 0 on a bad name, as bash does. Document execution-time alias expansion as a limitation.
** under globstar matches zero or more directories in any component position (files too when last), with relative output and bash's d/ vs d spelling for the zero-directory match. A trailing / keeps only directories and stays on each match (d/*/ -> d/e/).
A $ before ' or the closing " in double quotes starts no expansion
("$'q'" and "$"'q' print $'q' and $q); here-document bodies keep
$'a' as written. Function listings print $'...' as the single-quoted
text it decodes to and $"..." as "...", as bash does.
Mixed quoted/unquoted words now mark their quoted spans with the parser's quote-boundary markers, which parse_word turns into per-part quotedness, instead of in-band \x01/\x02 that expansion stripped from every value. Field splitting picks its protected-span markers from characters absent from the data, like the empty-field sentinel.
<(list) and >(list) no longer leak variable, cwd, option or $? changes into the parent shell, and exit inside one ends only the substitution. Document the remaining proc-sub gaps (/dev/fd/63 numbering, joining to adjacent word text) as limitations.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bashkit | 6fd50dd | Commit Preview URL Branch Preview URL |
Oct 08 2026, 04:31 AM |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Михайло · project thread
What changed
[[ == ]]always matches with extglob (bash 5.2).shopt nocasematchignores case forcase,[[ == / =~ ]]and${v/pat/rep}.!(..)can match an empty prefix; escaped\|and quoted text inside an extglob group are literal; an unbalanced group is plain text.${s:1:-1}counts back from the end, an out-of-range offset selects nothing, a negative array/$@length aborts withsubstring expression < 0, and${#@}/${#*}count positional parameters.**matches component by component with relative output (d/**givesd/), duplicates removed;d/*/keeps only directories with the slash.$'...': stays literal inside double quotes and here-documents;type/declare -fprint it back correctly.\x01/\x02markers, so values containing those bytes survive.<(..)/>(..)run in a subshell, so variables, cwd, options and$?no longer leak into the parent.Why
BashBox corpus batch: 24 of 29 skipped cases across shopt-pattern, word-expander, shopt, shopt-glob, ansi-c-quoting, marker-bytes and process-substitution now pass. The 5 left keep specific skip reasons: 4 expect
/dev/fd/63(bashkit uses per-tenant/dev/fd/proc_sub_<n>on purpose, see limitations), 1 needs read-time alias expansion.Before / After
ello [hello] 3/q/2extglob-in-cond/nocase/ell [] 2/$'q'/3Risk
[[ ]]now does extglob matching withoutshopt, which exposed exponential backtracking (+(a|aa)against 60 a's plusbhung). Every glob/extglob match now draws from a sharedMAX_GLOB_STEPSbudget (100k); TM-DOS-031 updated with a new test./skills/*/prints trailing slashes, and${arr[@]:1:-1}exits 1 with bash's error.Checklist
Generated by Claude Code