| 1 | #!/usr/bin/env bash |
| 2 | # |
| 3 | # NOTE: Could move spec/03-glob.sh here. |
| 4 | |
| 5 | #### glob double quote escape |
| 6 | echo "*.sh" |
| 7 | ## stdout: *.sh |
| 8 | |
| 9 | #### glob single quote escape |
| 10 | echo "*.sh" |
| 11 | ## stdout: *.sh |
| 12 | |
| 13 | #### glob backslash escape |
| 14 | echo \*.sh |
| 15 | ## stdout: *.sh |
| 16 | |
| 17 | #### 1 char glob |
| 18 | echo [b]in |
| 19 | ## stdout: bin |
| 20 | |
| 21 | #### 0 char glob -- does NOT work |
| 22 | echo []bin |
| 23 | ## stdout: []bin |
| 24 | |
| 25 | #### looks like glob at the start, but isn't |
| 26 | echo [bin |
| 27 | ## stdout: [bin |
| 28 | |
| 29 | #### looks like glob plus negation at the start, but isn't |
| 30 | echo [!bin |
| 31 | ## stdout: [!bin |
| 32 | |
| 33 | #### glob can expand to command and arg |
| 34 | spec/testdata/echo.s[hz] |
| 35 | ## stdout: spec/testdata/echo.sz |
| 36 | |
| 37 | #### glob after var expansion |
| 38 | touch _tmp/a.A _tmp/aa.A _tmp/b.B |
| 39 | f="_tmp/*.A" |
| 40 | g="$f _tmp/*.B" |
| 41 | echo $g |
| 42 | ## stdout: _tmp/a.A _tmp/aa.A _tmp/b.B |
| 43 | |
| 44 | #### quoted var expansion with glob meta characters |
| 45 | touch _tmp/a.A _tmp/aa.A _tmp/b.B |
| 46 | f="_tmp/*.A" |
| 47 | echo "[ $f ]" |
| 48 | ## stdout: [ _tmp/*.A ] |
| 49 | |
| 50 | #### glob after "$@" expansion |
| 51 | func() { |
| 52 | echo "$@" |
| 53 | } |
| 54 | func '_tmp/*.B' |
| 55 | ## stdout: _tmp/*.B |
| 56 | |
| 57 | #### glob after $@ expansion |
| 58 | func() { |
| 59 | echo $@ |
| 60 | } |
| 61 | func '_tmp/*.B' |
| 62 | ## stdout: _tmp/b.B |
| 63 | |
| 64 | #### no glob after ~ expansion |
| 65 | HOME=* |
| 66 | echo ~/*.py |
| 67 | ## stdout: */*.py |
| 68 | |
| 69 | #### store literal globs in array then expand |
| 70 | touch _tmp/a.A _tmp/aa.A _tmp/b.B |
| 71 | g=("_tmp/*.A" "_tmp/*.B") |
| 72 | echo ${g[@]} |
| 73 | ## stdout: _tmp/a.A _tmp/aa.A _tmp/b.B |
| 74 | ## N-I dash/ash stdout-json: "" |
| 75 | ## N-I dash/ash status: 2 |
| 76 | |
| 77 | #### glob inside array |
| 78 | touch _tmp/a.A _tmp/aa.A _tmp/b.B |
| 79 | g=(_tmp/*.A _tmp/*.B) |
| 80 | echo "${g[@]}" |
| 81 | ## stdout: _tmp/a.A _tmp/aa.A _tmp/b.B |
| 82 | ## N-I dash/ash stdout-json: "" |
| 83 | ## N-I dash/ash status: 2 |
| 84 | |
| 85 | #### glob with escaped - in char class |
| 86 | touch _tmp/foo.- |
| 87 | touch _tmp/c.C |
| 88 | echo _tmp/*.[C-D] _tmp/*.[C\-D] |
| 89 | ## stdout: _tmp/c.C _tmp/c.C _tmp/foo.- |
| 90 | |
| 91 | #### glob with char class expression |
| 92 | # note: mksh doesn't support [[:punct:]] ? |
| 93 | touch _tmp/e.E _tmp/foo.- |
| 94 | echo _tmp/*.[[:punct:]E] |
| 95 | ## stdout: _tmp/e.E _tmp/foo.- |
| 96 | ## BUG mksh stdout: _tmp/*.[[:punct:]E] |
| 97 | |
| 98 | #### glob double quotes |
| 99 | # note: mksh doesn't support [[:punct:]] ? |
| 100 | touch _tmp/\"quoted.py\" |
| 101 | echo _tmp/\"*.py\" |
| 102 | ## stdout: _tmp/"quoted.py" |
| 103 | |
| 104 | #### glob escaped |
| 105 | # - mksh doesn't support [[:punct:]] ? |
| 106 | # - python shell fails because \[ not supported! |
| 107 | touch _tmp/\[abc\] _tmp/\? |
| 108 | echo _tmp/\[???\] _tmp/\? |
| 109 | ## stdout: _tmp/[abc] _tmp/? |
| 110 | |
| 111 | #### : escaped |
| 112 | touch _tmp/foo.- |
| 113 | echo _tmp/*.[[:punct:]] _tmp/*.[[:punct\:]] |
| 114 | ## stdout: _tmp/foo.- _tmp/*.[[:punct:]] |
| 115 | ## BUG mksh stdout: _tmp/*.[[:punct:]] _tmp/*.[[:punct:]] |
| 116 | |
| 117 | #### Redirect to glob, not evaluated |
| 118 | # This writes to *.F, not foo.F |
| 119 | rm _tmp/*.F |
| 120 | touch _tmp/f.F |
| 121 | echo foo > _tmp/*.F |
| 122 | cat '_tmp/*.F' |
| 123 | ## status: 0 |
| 124 | ## stdout: foo |
| 125 | ## BUG bash status: 1 |
| 126 | ## BUG bash stdout-json: "" |
| 127 | |
| 128 | #### Glob after var manipulation |
| 129 | touch _tmp/foo.zzz _tmp/bar.zzz |
| 130 | g='_tmp/*.zzzZ' |
| 131 | echo $g ${g%Z} |
| 132 | ## stdout: _tmp/*.zzzZ _tmp/bar.zzz _tmp/foo.zzz |
| 133 | |
| 134 | #### Glob after part joining |
| 135 | touch _tmp/foo.yyy _tmp/bar.yyy |
| 136 | g='_tmp/*.yy' |
| 137 | echo $g ${g}y |
| 138 | ## stdout: _tmp/*.yy _tmp/bar.yyy _tmp/foo.yyy |
| 139 | |
| 140 | #### Glob flags on file system |
| 141 | touch _tmp/-n _tmp/zzzzz |
| 142 | cd _tmp |
| 143 | echo -* hello zzzz? |
| 144 | ## stdout-json: "hello zzzzz" |
| 145 | |
| 146 | #### set -o noglob |
| 147 | touch _tmp/spec-tmp/a.zz _tmp/spec-tmp/b.zz |
| 148 | echo _tmp/spec-tmp/*.zz |
| 149 | set -o noglob |
| 150 | echo _tmp/spec-tmp/*.zz |
| 151 | ## stdout-json: "_tmp/spec-tmp/a.zz _tmp/spec-tmp/b.zz\n_tmp/spec-tmp/*.zz\n" |
| 152 | |
| 153 | #### shopt -s nullglob |
| 154 | argv.py _tmp/spec-tmp/*.nonexistent |
| 155 | shopt -s nullglob |
| 156 | argv.py _tmp/spec-tmp/*.nonexistent |
| 157 | ## stdout-json: "['_tmp/spec-tmp/*.nonexistent']\n[]\n" |
| 158 | ## N-I dash/mksh/ash stdout-json: "['_tmp/spec-tmp/*.nonexistent']\n['_tmp/spec-tmp/*.nonexistent']\n" |
| 159 | |
| 160 | #### shopt -s failglob |
| 161 | argv.py *.ZZ |
| 162 | shopt -s failglob |
| 163 | argv.py *.ZZ # nothing is printed, not [] |
| 164 | echo status=$? |
| 165 | ## stdout-json: "['*.ZZ']\nstatus=1\n" |
| 166 | ## N-I dash/mksh/ash stdout-json: "['*.ZZ']\n['*.ZZ']\nstatus=0\n" |
| 167 | |
| 168 | #### Don't glob flags on file system with GLOBIGNORE |
| 169 | # This is a bash-specific extension. |
| 170 | expr $0 : '.*/osh$' >/dev/null && exit 99 # disabled until cd implemented |
| 171 | touch _tmp/-n _tmp/zzzzz |
| 172 | cd _tmp # this fail in osh |
| 173 | GLOBIGNORE=-*:zzzzz # colon-separated pattern list |
| 174 | echo -* hello zzzz? |
| 175 | ## stdout-json: "-* hello zzzz?\n" |
| 176 | ## N-I dash/mksh/ash stdout-json: "hello zzzzz" |
| 177 | ## status: 0 |
| 178 | |
| 179 | #### Splitting/Globbing doesn't happen on local assignment |
| 180 | f() { |
| 181 | # Dash splits words and globs before handing it to the 'local' builtin. But |
| 182 | # ash doesn't! |
| 183 | local foo=$1 |
| 184 | echo "$foo" |
| 185 | } |
| 186 | f 'void *' |
| 187 | ## stdout: void * |
| 188 | ## BUG dash stdout-json: "" |
| 189 | ## BUG dash status: 2 |
| 190 | |
| 191 | #### Glob of unescaped [[] and []] |
| 192 | touch $TMP/[ $TMP/] |
| 193 | cd $TMP |
| 194 | echo [\[z] [\]z] # the right way to do it |
| 195 | echo [[z] []z] # also accepted |
| 196 | ## STDOUT: |
| 197 | [ ] |
| 198 | [ ] |
| 199 | ## END |
| 200 | |
| 201 | #### Glob of negated unescaped [[] and []] |
| 202 | # osh does this "correctly" because it defers to libc! |
| 203 | touch $TMP/_G |
| 204 | cd $TMP |
| 205 | echo _[^\[z] _[^\]z] # the right way to do it |
| 206 | echo _[^[z] _[^]z] # also accepted |
| 207 | ## STDOUT: |
| 208 | _G _G |
| 209 | _G _G |
| 210 | ## END |
| 211 | ## BUG dash/mksh STDOUT: |
| 212 | _[^[z] _[^]z] |
| 213 | _[^[z] _[^]z] |
| 214 | ## END |
| 215 | |
| 216 | #### PatSub of unescaped [[] and []] |
| 217 | x='[foo]' |
| 218 | echo ${x//[\[z]/<} # the right way to do it |
| 219 | echo ${x//[\]z]/>} |
| 220 | echo ${x//[[z]/<} # also accepted |
| 221 | echo ${x//[]z]/>} |
| 222 | ## STDOUT: |
| 223 | <foo] |
| 224 | [foo> |
| 225 | <foo] |
| 226 | [foo> |
| 227 | ## END |
| 228 | ## N-I dash stdout-json: "" |
| 229 | ## N-I dash status: 2 |
| 230 | |
| 231 | #### PatSub of negated unescaped [[] and []] |
| 232 | x='[foo]' |
| 233 | echo ${x//[^\[z]/<} # the right way to do it |
| 234 | echo ${x//[^\]z]/>} |
| 235 | echo ${x//[^[z]/<} # also accepted |
| 236 | #echo ${x//[^]z]/>} # only busybox ash interprets as ^\] |
| 237 | ## STDOUT: |
| 238 | [<<<< |
| 239 | >>>>] |
| 240 | [<<<< |
| 241 | ## END |
| 242 | # mksh is doing something very odd, ignoring ^ altogether? |
| 243 | ## BUG mksh STDOUT: |
| 244 | <foo] |
| 245 | [foo> |
| 246 | <foo] |
| 247 | ## END |
| 248 | ## N-I dash stdout-json: "" |
| 249 | ## N-I dash status: 2 |