What are the contexts where Bash doesn't perform word splitting and globbing?

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?

Unix & Linux Asked on November 21, 2021

1 Answers

One Answer

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 expanded to a list with less or more than 1 element.

Answered by Stéphane Chazelas on November 21, 2021

Add your own answers!

Related Questions

How do I syntax check a Zsh script?

1  Asked on August 9, 2020 by akhil-jalagam


How can I swap my two screens, left to right?

5  Asked on August 4, 2020 by ripper234


Adding suffix to filename during for loop in bash

1  Asked on August 3, 2020 by mishal-ahmed


Why are aliases skipped if escaped?

2  Asked on August 2, 2020


Why can’t I type a g̃ the same way I type ñ?

1  Asked on July 29, 2020 by mmaluff


Custom logrotate with hostnames

0  Asked on July 29, 2020 by gwynn


Ask a Question

Get help from others!

© 2021 All rights reserved.