4882
Comment: align comments in one example, consistently capitalize Bash
|
12764
err, * must be inside too
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
"Glob" is the common name for a set of Bash features that match or expand specific types of patterns. Some synonyms for globbing (depending on the context in which it appears) are [http://tiswww.case.edu/php/chet/bash/bashref.html#SEC36 pattern matching], pattern expansion, filename expansion, and so on. A glob may look like {{{*.txt}}} and, when used to match filenames, is sometimes called a "wildcard". Traditional shell globs use a very simple syntax, which is less expressive than a regular expression. Most characters in a glob are treated literally, but a {{{*}}} matches 0 or more characters, a {{{?}}} matches precisely one character, and {{{[...]}}} matches any single character in a specified set (see the previous reference for details). All globs are implicitly anchored at both start and end. For example: || `*` || Matches any string, of any length || || `foo*` || Matches any string beginning with `foo` || || `*x*` || Matches any string containing an `x` (beginning, middle or end) || || `*.tar.gz` || Matches any string ending with `.tar.gz` || || `*.[ch]` || Matches any string ending with `.c` or `.h` || || `foo?` || Matches `foot` or `foo$` but not `fools` || |
<<TableOfContents>> = Globs = "Glob" is the common name for a set of Bash features that match or expand specific types of patterns. Some synonyms for globbing (depending on the context in which it appears) are [[http://tiswww.case.edu/php/chet/bash/bashref.html#SEC36|pattern matching]], pattern expansion, filename expansion, and so on. A glob may look like {{{*.txt}}} and, when used to match filenames, is sometimes called a "wildcard". Traditional shell globs use a very simple syntax, which is less expressive than a RegularExpression. Most characters in a glob are treated literally, but a {{{*}}} matches 0 or more characters, a {{{?}}} matches precisely one character, and {{{[...]}}} matches any single character in a specified set (see [[#Ranges|Ranges]] below). All globs are implicitly anchored at both start and end. For example: ||`*` ||Matches any string, of any length || ||`foo*` ||Matches any string beginning with `foo` || ||`*x*` ||Matches any string containing an `x` (beginning, middle or end) || ||`*.tar.gz` ||Matches any string ending with `.tar.gz` || ||`*.[ch]` ||Matches any string ending with `.c` or `.h` || ||`foo?` ||Matches `foot` or `foo$` but not `fools` || |
Line 14: | Line 18: |
{{{tar xvf *.tar | {{{#!highlight bash tar xvf *.tar |
Line 16: | Line 21: |
# (which is generally not what one wants)}}} | # (which is generally not what one wants) }}} |
Line 20: | Line 26: |
{{{# This is safe even if a filename contains whitespace: | {{{#!highlight bash # This is safe even if a filename contains whitespace: |
Line 28: | Line 35: |
done}}} In the second example above, the output of {{{ls}}} is filtered, and then the result of the whole pipeline is divided into words, to serve as iterative values for the loop. This word-splitting will occur at internal whitespace within each filename, which makes it useless in the general case. The first example has no such problem, because the filenames produced by the glob do ''not'' undergo any further word-splitting. For more such examples, see BashPitfalls. Globs are also used to match patterns in a few places in Bash. The most traditional is in the {{{case}}} command: {{{case "$input" in |
done }}} In the second example above, the output of {{{ls}}} is filtered, and then the result of the whole pipeline is [[WordSplitting|divided into words]], to serve as iterative values for the loop. This word-splitting will occur at internal whitespace within each filename, which makes it useless in the general case. The first example has no such problem, because the filenames produced by the glob do ''not'' undergo any further word-splitting. For more such examples, see BashPitfalls. Globs are also used to match patterns in a few places in Bash. The most traditional is in the [[BashGuide/TestsAndConditionals#Choices|case]] command: {{{#!highlight bash case "$input" in |
Line 38: | Line 47: |
esac}}} | esac }}} |
Line 44: | Line 54: |
{{{if [[ $output = *[Ee]rror* ]]; then ... }}} Finally, globs are used during [:BashFAQ#faq73:parameter expansion] to indicate patterns which may be stripped out, or replaced, during a substitution. Simple examples (there are many more on the previously referenced page): {{{ |
{{{#!highlight bash if [[ $output = *[Ee]rror* ]]; then ... }}} Finally, globs are used during [[BashFAQ/073|parameter expansion]] to indicate patterns which may be stripped out, or replaced, during a substitution. Simple examples (there are many more on the previously referenced page): {{{#!highlight bash |
Line 53: | Line 64: |
IFS=$'\n'; echo "${arr[*]}" # dump an array, one element per line IFS=$'\n'; echo "${arr[*]/error*/}" # dump array, removing error* if matched unset IFS}}} In addition to the traditional globs (supported by all Bourne-family shells) that we've seen so far, Bash (and Korn Shell) offers ''extended globs'', which have the expressive power of regular expressions. Korn shell enables these by default; in Bash, you must run the command {{{shopt -s extglob }}} in your shell (or at the start of your script) to use them. The [http://tiswww.case.edu/php/chet/bash/bashref.html#SEC36 pattern matching reference] describes the syntax, which is reproduced here: |
printf '%s\n' "${arr[@]}" # dump an array, one element per line printf '%s\n' "${arr[@]/error*/}" # dump array, removing error* if matched }}} (Reference: [[BashGuide/Arrays|Arrays]] [[Quotes]] [[http://bash-hackers.org/wiki/doku.php/commands/builtin/printf|printf]].) == Ranges == Globs can specify a ''range'' or ''class'' of characters, using square brackets. This gives you the ability to match against a set of characters. For example: ||`[abcd]` ||Matches `a` or `b` or `c` or `d`|| ||`[a-d]` ||The same as above, if ''globasciiranges'' is set or your [[locale]] is C or POSIX. Otherwise, implementation-defined.|| ||`[!aeiouAEIOU]` ||Matches any character ''except'' `a`, `e`, `i`, `o`, `u` and their uppercase counterparts|| ||`[[:alnum:]]` ||Matches any alphanumeric character in the current locale (letter or number)|| ||`[[:space:]]` ||Matches any whitespace character|| ||`[![:space:]]` ||Matches any character that is ''not'' whitespace|| ||`[[:digit:]_.]` ||Matches any digit, or `_` or `.`|| === globasciiranges (since bash 4.3-alpha) === Interprets [a-d] as [abcd]. To match a literal -, include it as first or last character. === For older versions === Note that ''Implementation-defined'' means it may work as you expect on one machine, but give completely different results on another machine. Do not use the `m-n` syntax unless you have explicitly set your locale to C first, or you may get unexpected results. The [[http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_03_05|POSIX character class expressions]] should be preferred whenever possible. == Options which change globbing behavior == === extglob === In addition to the traditional globs (supported by all Bourne-family shells) that we've seen so far, Bash (and Korn Shell) offers ''extended globs'', which have the expressive power of [[RegularExpression|regular expressions]]. Korn shell enables these by default; in Bash, you must run the command {{{#!highlight bash shopt -s extglob }}} in your shell (or at the ''start'' of your script -- see note on parsing below) to use them. The [[http://tiswww.case.edu/php/chet/bash/bashref.html#SEC36|pattern matching reference]] describes the syntax, which is reproduced here: |
Line 70: | Line 108: |
Patterns in a list are separated by `|` characters. |
|
Line 72: | Line 112: |
{{{# To remove all the files except ones matching *.jpg rm !(*.jpg)}}} {{{# To copy all the MP3 songs except one to your device cp !(04*).mp3 /mnt}}} {{{# To trim leading and trailng whitespace from a variable x=${x##+([[:space:]])}; x=${x%%+([[:space:]])} }}} |
{{{#!highlight bash # To remove all the files except ones matching *.jpg: rm !(*.jpg) # All except *.jpg and *.gif and *.png: rm !(*.jpg|*.gif|*.png) }}} {{{#!highlight bash # To copy all the MP3 songs except one to your device cp !(04*).mp3 /mnt }}} To use an extglob in a parameter expansion (this can also be done in one BASH statement with [[BashFAQ/067|read]]): {{{#!highlight bash # To trim leading and trailing whitespace from a variable x=${x##+([[:space:]])}; x=${x%%+([[:space:]])} }}} Extended glob patterns can be nested, too. {{{#!highlight bash [[ $fruit = @(ba*(na)|a+(p)le) ]] && echo "Nice fruit" }}} '''`extglob` changes the way certain characters are parsed. It is necessary to have a newline (not just a semicolon) between `shopt -s extglob` and any subsequent commands to use it.''' You cannot enable extended globs inside a [[BashGuide/CompoundCommands#Command\ Grouping|group command]] that uses them, because the entire block is parsed before the `shopt` is ''evaluated''. Note that the typical [[BashGuide/CompoundCommands#Functions|function]] body ''is'' a ''group command''. An unpleasant workaround could be to use a ''subshell command list'' as the function body. Therefore, if you use this option in a script, it is best put right under the shebang line. {{{#!highlight bash #!/usr/bin/env bash shopt -s extglob # and others, such as nullglob dotglob }}} If your code must be sourced and needs `extglob`, ensure it preserves the original setting from your shell: {{{#!highlight bash # remember whether extglob was originally set, so we know whether to unset it shopt -q extglob; extglob_set=$? # set extglob if it wasn't originally set. ((extglob_set)) && shopt -s extglob # Note, 0 (true) from shopt -q is "false" in a math context. # The basic concept behind the following is to delay parsing of the globs until evaluation. # This matters at group commands, such as functions in { } blocks declare -a s='( !(x) )' echo "${s[@]}" echo "${InvalidVar:-!(x)}" eval 'echo !(x)' # using eval if no other option. # unset extglob if it wasn't originally set ((extglob_set)) && shopt -u extglob }}} This should also apply for other shell options. === nullglob === If a glob fails to match any filenames, the shell normally leaves it alone. This means the raw glob will be passed on to the command, as in: {{{#!highlight bash $ ls *.ttx ls: cannot access *.ttx: No such file or directory }}} This allows the command to see the glob you used, and to use it in an error message. If the Bash option '''nullglob''' is set, however, a glob which matches no files will be removed entirely. This is [[BashFAQ/004|useful in scripts]], but somewhat confusing at the command line, since it "breaks" the expectations of many of the standard tools (see failglob below for a better alternative): {{{#!highlight bash # Good in scripts! shopt -s nullglob oggs=(*.ogg) for ogg in "${oggs[@]}"; do ... # Bad at the command line! shopt -s nullglob ls *.ttx # Runs "ls" with no arguments, and lists EVERYTHING }}} === dotglob === By convention, a filename beginning with a dot is "hidden", and not shown by `ls`. Globbing uses the same convention -- filenames beginning with a dot are not matched by a glob, unless the glob also begins with a dot. Bash has a '''dotglob''' option that lets globs match "dot files": {{{#!highlight bash shopt -s dotglob nullglob files=(*) echo "There are ${#files[@]} files here, including dot files and subdirs" }}} It should be noted that when `dotglob` is enabled, `*` will match files like `.bashrc` but ''not'' the `.` or `..` directories. This is orthogonal to the problem of matching "just the dot files" -- a glob of `.*` ''will'' match `.` and `..`, typically causing problems. === globstar (since bash 4.0-alpha) === To recurse … {{{#!highlight bash shopt -s globstar files=(*) echo "There are ${#files[@]} files here, including dot files and subdirs" }}} === failglob === If a pattern fails to match, bash reports an expansion error. This can be useful at the commandline: {{{#!highlight bash # Good at the command line! $ touch *.foo # creates file '*.foo' if glob fails to match $ shopt -s failglob $ touch *.foo # touch doesn't get executed -bash: no match: *.foo }}} === GLOBIGNORE === The Bash variable (not shopt) `GLOBIGNORE` allows you to specify patterns a glob ''should not'' match. This lets you work around the infamous "I want to match all of my dot files, but not . or .." problem: {{{#!highlight bash $ echo .* . .. .bash_history .bash_logout .bashrc .inputrc .vimrc $ GLOBIGNORE=.:.. $ echo .* .bash_history .bash_logout .bashrc .inputrc .vimrc }}} Unset GLOBIGNORE {{{#!highlight bash $ GLOBIGNORE= $ echo .* . .. .bash_history .bash_logout .bashrc .inputrc .vimrc }}} === nocasematch === Globs inside [[ and case commands are matched case-insensitive: {{{#!highlight bash foo() { local f r=0 nc=0 shopt -q nocasematch && nc=1 || shopt -s nocasematch for f; do [[ $f = *.@(txt|jpg) ]] || continue cmd -on "$f" || r=1 done ((nc)) || shopt -u nocasematch return $r } }}} This is conventionally done this way: {{{#!highlight bash case $f in *.[Tt][Xx][Tt]|*.[Jj][Pp][Gg]) : ;; *) continue esac }}} and in earlier versions of bash we'd use a similar glob: {{{#!highlight bash [[ $f = *.@([Tt][Xx][Tt]|[Jj][Pp][Gg]) ]] || continue }}} or with no extglob: {{{#!highlight bash [[ $f = *.[Tt][Xx][Tt] ]] || [[ $f = *.[Jj][Pp][Gg] ]] || continue }}} Here, one might keep the tests separate for maintenance; they can be easily reused and dropped, without having to concern oneself with where they fit in relation to an internal ||. Note also: {{{#!highlight bash [[ $f = *.@([Tt][Xx][Tt]|[Jj][Pp]?([Ee])[Gg]) ]] }}} Variants left as an exercise. === nocaseglob (since bash 2.02-alpha1) === This option makes ''pathname expansion'' case-insensitive. In contrast, [[#nocasematch|nocasematch]] operates on matches in ''[[BashGuide/TestsAndConditionals#Conditional_Blocks|[[]]'' and ''[[BashGuide/TestsAndConditionals#Choices|case]]'' commands. ---- CategoryShell |
Contents
Globs
"Glob" is the common name for a set of Bash features that match or expand specific types of patterns. Some synonyms for globbing (depending on the context in which it appears) are pattern matching, pattern expansion, filename expansion, and so on. A glob may look like *.txt and, when used to match filenames, is sometimes called a "wildcard".
Traditional shell globs use a very simple syntax, which is less expressive than a RegularExpression. Most characters in a glob are treated literally, but a * matches 0 or more characters, a ? matches precisely one character, and [...] matches any single character in a specified set (see Ranges below). All globs are implicitly anchored at both start and end. For example:
* |
Matches any string, of any length |
foo* |
Matches any string beginning with foo |
*x* |
Matches any string containing an x (beginning, middle or end) |
*.tar.gz |
Matches any string ending with .tar.gz |
*.[ch] |
Matches any string ending with .c or .h |
foo? |
Matches foot or foo$ but not fools |
Bash expands globs which appear unquoted in commands, by matching filenames relative to the current directory. The expansion of the glob results in 1 or more words (0 or more, if certain options are set), and those words (filenames) are used in the command. For example:
Even if a file contains internal whitespace, the expansion of a glob that matches that file will still preserve each filename as a single word. For example,
In the second example above, the output of ls is filtered, and then the result of the whole pipeline is divided into words, to serve as iterative values for the loop. This word-splitting will occur at internal whitespace within each filename, which makes it useless in the general case. The first example has no such problem, because the filenames produced by the glob do not undergo any further word-splitting. For more such examples, see BashPitfalls.
Globs are also used to match patterns in a few places in Bash. The most traditional is in the case command:
Patterns (which are separated by | characters) are matched against the first word after the case itself. The first pattern which matches, "wins", causing the corresponding commands to be executed.
Bash also allows globs to appear on the right-hand side of a comparison inside a [[ command:
1 if [[ $output = *[Ee]rror* ]]; then ...
Finally, globs are used during parameter expansion to indicate patterns which may be stripped out, or replaced, during a substitution. Simple examples (there are many more on the previously referenced page):
(Reference: Arrays Quotes printf.)
Ranges
Globs can specify a range or class of characters, using square brackets. This gives you the ability to match against a set of characters. For example:
[abcd] |
Matches a or b or c or d |
[a-d] |
The same as above, if globasciiranges is set or your locale is C or POSIX. Otherwise, implementation-defined. |
[!aeiouAEIOU] |
Matches any character except a, e, i, o, u and their uppercase counterparts |
[[:alnum:]] |
Matches any alphanumeric character in the current locale (letter or number) |
[[:space:]] |
Matches any whitespace character |
[![:space:]] |
Matches any character that is not whitespace |
[[:digit:]_.] |
Matches any digit, or _ or . |
globasciiranges (since bash 4.3-alpha)
Interprets [a-d] as [abcd]. To match a literal -, include it as first or last character.
For older versions
Note that Implementation-defined means it may work as you expect on one machine, but give completely different results on another machine. Do not use the m-n syntax unless you have explicitly set your locale to C first, or you may get unexpected results. The POSIX character class expressions should be preferred whenever possible.
Options which change globbing behavior
extglob
In addition to the traditional globs (supported by all Bourne-family shells) that we've seen so far, Bash (and Korn Shell) offers extended globs, which have the expressive power of regular expressions. Korn shell enables these by default; in Bash, you must run the command
1 shopt -s extglob
in your shell (or at the start of your script -- see note on parsing below) to use them. The pattern matching reference describes the syntax, which is reproduced here:
- ?(pattern-list)
- Matches zero or one occurrence of the given patterns.
- *(pattern-list)
- Matches zero or more occurrences of the given patterns.
- +(pattern-list)
- Matches one or more occurrences of the given patterns.
- @(pattern-list)
- Matches one of the given patterns.
- !(pattern-list)
- Matches anything except one of the given patterns.
Patterns in a list are separated by | characters.
Extended globs allow you to solve a number of problems which otherwise require a rather surprising amount of ugly hacking; for example,
To use an extglob in a parameter expansion (this can also be done in one BASH statement with read):
Extended glob patterns can be nested, too.
1 [[ $fruit = @(ba*(na)|a+(p)le) ]] && echo "Nice fruit"
extglob changes the way certain characters are parsed. It is necessary to have a newline (not just a semicolon) between shopt -s extglob and any subsequent commands to use it. You cannot enable extended globs inside a group command that uses them, because the entire block is parsed before the shopt is evaluated. Note that the typical function body is a group command. An unpleasant workaround could be to use a subshell command list as the function body.
Therefore, if you use this option in a script, it is best put right under the shebang line.
If your code must be sourced and needs extglob, ensure it preserves the original setting from your shell:
1 # remember whether extglob was originally set, so we know whether to unset it
2 shopt -q extglob; extglob_set=$?
3 # set extglob if it wasn't originally set.
4 ((extglob_set)) && shopt -s extglob
5 # Note, 0 (true) from shopt -q is "false" in a math context.
6
7 # The basic concept behind the following is to delay parsing of the globs until evaluation.
8 # This matters at group commands, such as functions in { } blocks
9
10 declare -a s='( !(x) )'
11 echo "${s[@]}"
12
13 echo "${InvalidVar:-!(x)}"
14
15 eval 'echo !(x)' # using eval if no other option.
16
17 # unset extglob if it wasn't originally set
18 ((extglob_set)) && shopt -u extglob
This should also apply for other shell options.
nullglob
If a glob fails to match any filenames, the shell normally leaves it alone. This means the raw glob will be passed on to the command, as in:
This allows the command to see the glob you used, and to use it in an error message. If the Bash option nullglob is set, however, a glob which matches no files will be removed entirely. This is useful in scripts, but somewhat confusing at the command line, since it "breaks" the expectations of many of the standard tools (see failglob below for a better alternative):
dotglob
By convention, a filename beginning with a dot is "hidden", and not shown by ls. Globbing uses the same convention -- filenames beginning with a dot are not matched by a glob, unless the glob also begins with a dot. Bash has a dotglob option that lets globs match "dot files":
It should be noted that when dotglob is enabled, * will match files like .bashrc but not the . or .. directories. This is orthogonal to the problem of matching "just the dot files" -- a glob of .* will match . and .., typically causing problems.
globstar (since bash 4.0-alpha)
To recurse …
failglob
If a pattern fails to match, bash reports an expansion error. This can be useful at the commandline:
GLOBIGNORE
The Bash variable (not shopt) GLOBIGNORE allows you to specify patterns a glob should not match. This lets you work around the infamous "I want to match all of my dot files, but not . or .." problem:
Unset GLOBIGNORE
nocasematch
Globs inside [[ and case commands are matched case-insensitive:
This is conventionally done this way:
and in earlier versions of bash we'd use a similar glob:
1 [[ $f = *.@([Tt][Xx][Tt]|[Jj][Pp][Gg]) ]] || continue
or with no extglob:
1 [[ $f = *.[Tt][Xx][Tt] ]] || [[ $f = *.[Jj][Pp][Gg] ]] || continue
Here, one might keep the tests separate for maintenance; they can be easily reused and dropped,
without having to concern oneself with where they fit in relation to an internal ||.
Note also:
1 [[ $f = *.@([Tt][Xx][Tt]|[Jj][Pp]?([Ee])[Gg]) ]]
Variants left as an exercise.
nocaseglob (since bash 2.02-alpha1)
This option makes pathname expansion case-insensitive. In contrast, nocasematch operates on matches in [[ and case commands.