Bash doesn't perform word splitting in globbing in these cases:

  • LHS or RHS of an assignment, except for indexed arrays
    var=$value                                # simple variable
    declare -A hash
    key="key with a space"
    hash[$key]=$value                         # index of an associative array
    arr=$(echo "1 2 3")                       # word splitting does happen here
  • Inside [[ ]]
    var="one two"
    if [[ $var = *" "* ]]; then ...           # check if var has a space in it
    if [[ $(echo "one two") = $var ]]; then   # use the output of command substitution to compare with var
  • Inside (( ))
    ((sum = $(echo "99 + 1")))                  # assigns 100 to sum
  • In herestring
    cat <<< *                                 # gives '*' as the output

Is there a definite list of cases where Bash does or doesn't perform word splitting and globbing?

  • cat <<< $var does word splitting (followed by joining with space) but not globbing in older versions. For redirections, that depends on whether the posix/sh mode is enabled and the shell is interactive or not. May 4, 2018 at 13:18
  • Note that "indexed array" is the retronym for ordinary arrays, in contrast to associative array. You are talking about the index to an associative array.
    – chepner
    May 4, 2018 at 17:43
  • 1
    case $foo in is another. I'm not sure about arguments to parameter expansion; foo="a * b" survives unexpanded in both "${bar:-$foo}" and ${bar:-"$foo"}. I don't recall the details, but I think there is a comment in the source to the effect that the argument itself is not subject to word-splitting or pathname expansion.
    – chepner
    May 4, 2018 at 17:51
  • I asked the same question on StackOverflow to see if it gets more attention there. May 25, 2018 at 23:30

1 Answer 1


That's typically the cases where it can't or it wouldn't make sense, so the non-list contexts. There are however non-list contexts where it does it, but complains when it results in more than one item, or joins those items with spaces.

Also, it's important to make the distinction between just wildcard pattern matching and filename generation or globbing, which is the generation of a list of file names that match a pattern.

For instance in [[ foo = * ]], there is no globbing, as in that * is not expanded to the list of non-hidden files in the current directory, but that * is still interpreted as a pattern (here it returns true as foo matches the * pattern).

By splitting here, we're referring to the implicit splitting that is done upon unquoted parameter expansion ($param), command substitution ($(...) and `...`), and arithmetic expansion ($((...)) and $[...]), using the $IFS special parameter in list contexts.

We'll take * as an example below. As a pattern, it matches any sequence of characters. As a glob it expands to all the non-hidden files in the current directory (subject to dotglob, GLOBIGNORE...).

The below applies to bash, there are variations in other shells.

Cases where splitting and globbing don't occur:

  • when quoted (with '*', "*", \*, $'*', $"*").

  • inside here documents (whether the delimiter is quoted or not):

    cat << EOF
    cat << 'EOF'
  • inside arithmetic expressions:

    • echo $((2 * 2)) (* is not globbed but $((...)) undergoes split+glob, try after IFS=4)
    • array[2 * 2]=4 / ${array[2 * 2]} / exec {array[2*2]}>&1. Beware that you need the quotes in unset -v 'a[1]' ([1] is a wildcard).
    • ((2 * 2))
    • echo $[2 * 2]
  • scalar variable assignment:

    • var=*
    • array[x]=*
    • hash[key]=*
    • array=([1]=*) (older versions of bash used to do globbing there though and do something different when there was a file called 1=foo in the current directory for instance).
    • var+=*
  • in associative array keys:

    • typeset -A hash; hash[**]=value; v=${hash[**]}. * and @ are special though.
  • in assignments after export/local/typeset/declare/readonly under some circumstances only: the assignment keyword and the variable name and = must not be quoted even in part, and not be the result of any expansion. assignments and redirections may occurs before, but command can't be used.:

    • OK (no split+glob):
      • export a=*
      • x=1 < /dev/null export foo a=*
    • not OK (split+glob performed):
      • ""export a=*
      • command export a=* (except in POSIX mode)
      • export "a"=*
      • export a\=*
      • "$(echo export)" a=*

    more on that at Are quotes needed for local variable assignment?

  • case * in (...); esac

  • case x in (*); esac (no split+glob, but that * is treated as a pattern, that also applies to wildcard found inside unquoted expansions as in var=*; case x in ($var)).

  • inside [[...]]. Though note that pattern matching is done if unquoted wildcards are present on the right hand side of =, ==, != operators there.

  • in here strings since version 4.4. In earlier versions, splitting (though not globbing) was done and the resulting words joined with spaces.

  • in the target of redirections when the shell is in POSIX mode and non-interactive: bash -o posix -c 'echo test > *'. Otherwise, split+glob will be performed and bash will report an error if that expands to a list with less or more than 1 element.

  • I hesitate, but may I add to @Stéphane 's list the body of a function definition? In fun() { echo a * b; }, the a * b remains as is, and is splitted and globbed only when calling fun.
    – db-inf
    Feb 14 at 15:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .