[] denotes a character class. Simply put, a character class is a way to designate a character set in a way that matches a single character . [AZ] is a very common example - it matches all alphabets from A to Z
The following are the results of the commands in the new directory:
$ echo [s] [s] $ echo [t] [t] $ echo [ t ] [ t ] $ echo [root] [root]
As you can see, echo displays them as is. What for? Read the next section.
Expansion
Each time you type a command into a terminal and press the ENTER key, bash performs many operations internally before printing the results to the shell. The simplest example is the * extension:
$ echo * evil_plans.txt dir1 dir2
Instead of printing the literal * as output, he printed the contents of the directory. Why did this happen? Because * has a special meaning - it is a wildcard that can match any character in the file name. It is important to note that the echo command does not see * at all - only an extended result.
There are different types of extensions:
- Bracket Extension
- Tilda Extension
- Parameter Extension
- Team extension
- Arithmetic expansion
- Process replacement
- File name extension
... and probably more. In this case, the file name extension is the appropriate type of extension.
File name extension
When you enter the echo command and press ENTER, bash processes the command and breaks it into words. Once this is done, it scans words for the following characters ? , * and [ . All these are metacharacters and have special meaning. If bash detects any of these characters to appear, it treats the supplied word as a pattern.
For example, consider the following case:
$ touch foobar foobak fooqux barbar boofar $ echo foo* foobar foobak fooqux
As you can see, * expanded and listed matching file names. (In this case, those starting with foo .)
Now try another example:
$ touch gray.txt grey.txt $ echo gr?y.txt gray.txt grey.txt
? matches one character. Nothing more. In this case, gray.txt and grey.txt same as the template, so both were printed.
Another example:
$ touch hello hullo hallo $ echo h[aeu]llo hallo hello hullo
What happened here? As you know, [aeu] is a character class. A character class corresponds to just one of the characters in it; it never matches more than one character. In this case, the characters in the character class may correctly match the file names, so the results were printed.
If no matching file names are found, the word remains unchanged.
Explanation for your specific case
$ echo [s]
[s] is a character class and corresponds to only one character - the literal s . But no matching files were found, so it was returned as is.
$ echo [t]
[t] also a character class. It matches a single character. In your directory there was a file called t , that is, there was a match. Thus, it returned the name of the found file name.
$ echo [root]
[root] matches the following characters: r , o , t . As you probably guessed, o , which occurs twice in the character class, does not matter here. A character class can match only one character. So echo [root] will try to find the names of files that have the corresponding character. Since there is a file named t in your directory, it is listed.
How to avoid such quirks?
Always use quotes and escapes if necessary. They give you general control over the results of parsing, expansion, and expansion.