This command allows you to do various tests and sets its exit code to 0 (//TRUE//) or 1 (//FALSE//) whenever such a test succeeds or not. Using this exit code, it's possible to let Bash react on the result of such a test, here by using the command in an if-statement:
The syntax of the test command is relatively easy. Usually it's the command name "''test''" followed by a test type (here "''-e''" for "file exists") followed by test-type-specific values (here the filename to check, "''/etc/passwd''").
There's a second standardized command that does exactly the same: the command "''[''" - the difference just is that it's called "''[''" and the last argument to the command must be a "'']''": It forms "''**[ <EXPRESSION> ]**''"
One might **think** now that these "[" and "]" belong to the syntax of Bash's if-clause: **No they don't! It's a simple, ordinary command, still!**
Another thing you have to remember is that if the test command wants one parameter for a test, you have to give it one parameter. Let's check for some of your music files:
As you definitely noted, the filename contains spaces. Since we call a normal ordinary command ("test" or "[") the shell will word-split the expansion of the variable ''mymusic'': You need to quote it when you don't want the ''test''-command to complain about too many arguments for this test-type! If you didn't understand it, please read the [[syntax:words | article about words...]]
Please also note that the file-tests want **one filename** to test. Don't give a glob (filename-wildcards) as it can expand to many filenames => **too many arguments!**
This provides exactly **one** test-argument to the command. With one parameter, it defaults to the ''-n'' test: It tests if a provided string is empty (''FALSE'') or not (''TRUE'') - due to the lack of **spaces to separate the arguments** the shown command always ends ''TRUE''!
Well, I addressed several basic rules, now let's see what the test-command can do for you. The Bash test-types can be split into several sections: **file tests**, **string tests**, **arithmetic tests**, **misc tests**.
Below, the tests marked with :!: are non-standard tests (i.e. not in SUS/POSIX/etc..).
===== File tests =====
This section probably holds the most tests, I'll list them in some logical order. Since Bash 4.1, all tests related to permissions respect ACLs, if the underlying filesystem/OS supports them.
|**-n** <STRING>|True, if <STRING> is **not empty** (this is the default operation).|
|<STRING1> **=** <STRING2>|True, if the strings are **equal**.|
|<STRING1> **!=** <STRING2>|True, if the strings are **not equal**.|
|<STRING1> **<** <STRING2>|True if <STRING1> sorts **before** <STRING2> lexicographically (pure ASCII, not current locale!). Remember to escape! Use ''\<''|
|<STRING1> **>** <STRING2>|True if <STRING1> sorts **after** <STRING2> lexicographically (pure ASCII, not current locale!). Remember to escape! Use ''\>''|
| <TEST1> **-a** <TEST2> | True, if <TEST1> **and** <TEST2> are true (AND). Note that ''-a'' also may be used as a file test (see above) |
| <TEST1> **-o** <TEST2> | True, if either <TEST1> **or** <TEST2> is true (OR). |
| **!** <TEST> | True, if <TEST> is **false** (NOT). |
| **(** <TEST> **)** | Group a test (for precedence). **Attention:** In normal shell-usage, the "(" and ")" must be escaped; use "\(" and "\)"! |
| **-o** <OPTION_NAME> | True, if the [[internals:shell_options| shell option]] <OPTION_NAME> is set. |
| **-v** <VARIABLENAME> | True if the variable <VARIABLENAME> has been set. Use ''var[n]'' for array elements. |
| **-R** <VARIABLENAME> | True if the variable <VARIABLENAME> has been set and is a nameref variable (since 4.3-alpha) |
The ''test'' builtin, especially hidden under its ''['' name, may seem simple but is in fact **causing a lot of trouble sometimes**.
One of the difficulty is that the behaviour of ''test'' not only depends on its arguments but also on the **number of its arguments**.
Here are the rules taken from the manual (__**Note:**__ This is for the command ''test'', for ''['' the number of arguments is calculated without the final '']'', for example ''[ ]'' follows the "zero arguments" rule):
* **0 arguments**
* The expression is false.
* **1 argument**
* The expression is true if, and only if, the argument is not null
* **2 arguments**
* If the first argument is ''!'' (exclamation mark), the expression is true if, and only if, the second argument is null
* If the first argument is one of the unary conditional operators listed above under the syntax rules, the expression is true if the unary test is true
* If the first argument is not a valid unary conditional operator, the expression is false
* **3 arguments**
* If the second argument is one of the binary conditional operators listed above under the syntax rules, the result of the expression is the result of the binary test using the first and third arguments as operands
* If the first argument is ''!'', the value is the negation of the two-argument test using the second and third arguments
* If the first argument is exactly ''('' and the third argument is exactly '')'', the result is the one-argument test of the second argument. Otherwise, the expression is false. The ''-a'' and ''-o'' operators are considered binary operators in this case (**Attention:** This means the operator ''-a'' is not a file operator in this case!)
* **4 arguments**
* If the first argument is ''!'', the result is the negation of the three-argument expression composed of the remaining arguments. Otherwise, the expression is parsed and evaluated according to precedence using the rules listed above
* **5 or more arguments**
* The expression is parsed and evaluated according to precedence using the rules listed above
These rules may seem complex, but it's not so bad in practice. Knowing them might help you to explain some of the "unexplicable" behaviours you might encounter:
This code prints "var is not empty", even though ''-n something'' is supposed to be true if ''$var'' is not empty - **why?**
Here, as ''$var'' is **not quoted**, word splitting occurs and ''$var'' results in actually nothing (Bash removes it from the command's argument list!). So the test is in fact ''[ -n ]'' **and falls into the "one argument" rule**, the only argument is "-n" which is not null and so the test returns true. The solution, as usual, is to **quote the parameter expansion**: ''[ -n "$var" ]'' so that the test has always 2 arguments, even if the second one is the null string.
These rules also explain why, for instance, -a and -o can have several meanings.
The way often recommended to logically connect several tests with AND and OR is to use **several single test commands** and to **combine** them with the shell ''&&'' and ''||'' **list control operators**.
You might find the error message confusing, ''['' does not find the required final '']'', because as seen above ''&&'' is used to write a **list of commands**. The ''if'' statement actually **sees two commands**:
POSIX(r)/SUSv3 does **not** specify the behaviour of ''test'' in cases where there are more than 4 arguments. If you write a script that might not be executed by Bash, the behaviour might be different! ((<rant>Of course, one can wonder what is the use of including the parenthesis in the specification without defining the behaviour with more than 4 arguments or how usefull are the examples with 7 or 9 arguments attached to the specification.</rant>))
=> Due to the nature of the ''&&'' list operator, the second test-command runs only if the first test-command returns true, our echo-command **is not executed**.
For the test command, the precedence parenthesis are, as well, ''( )'', but you need to escape or quote them, so that the shell doesn't try to interpret them:
Unlike for AND and OR, both methods for NOT have an identical behaviour, at least for doing one single test.
===== Pitfalls summarized =====
In this section you will get all the mentioned (and maybe more) possible pitfalls and problems in a summary.
==== General ====
Here's the copy of a mail on bug-bash list. A user asking a question about using the test command in Bash, **he's talking about a problem, which you may have already had yourself**:
He simply didn't know that ''test'' or ''['' is a normal, simple command. Well, here's the answer he got. I quote it here, because it's a well written text that addresses most of the common issues with the "classic" test command:
I hope this text protects you a bit from stepping from one pitfall into the next.
I find it very interesting and informative, that's why I quoted it here. Many thanks, Bob, also for the permission to copy the text here!
===== Code examples =====
==== Snipplets ====
Some code snipplets follow, different ways of shell reaction is used.
* **check if a variable is defined/non-NULL**
* ''test "$MYVAR"''
* ''[ "$MYVAR" ]''
* **Note:** There are possibilities to make a difference if a variable is //undefined// or //NULL// - see [[syntax:pe#use_an_alternate_value|Parameter Expansion - Using an alternate value]]
* **check if a directory exists, if not, create it**
Using a [[syntax:ccmd:classic_for | for-loop]] to iterate through all entries of a directory, if an entry is a directory (''[ -d "$fn" ]''), print its name: