Test is used by virtually every shell script written. It may not seem that way, becausetest is not often called directly.test is more frequentlycalled as [. [ is a symbolic link totest, just to make shell programs morereadable. If is also normally a shell builtin (which means that the shell itself will interpret[ as meaning test, even if your Unix environment is set up differently):
$ type [ [ is a shell builtin $ which [ /usr/bin/[ $ ls -l /usr/bin/[ lrwxrwxrwx 1 root root 4 Mar 27 2000 /usr/bin/[ -> test
This means that '[' is actually a program, just like ls and other programs, so it must besurrounded by spaces:
if [$foo == "bar" ]
will not work; it is interpreted as if test$foo == "bar" ], which is a ']' without a beginning '['.Put spaces around all your operators I've highlighted the mandatory spaces with the word 'SPACE' - replace 'SPACE'with an actual space; if there isn't a space there, it won't work:
if SPACE [ SPACE "$foo" SPACE == SPACE "bar" SPACE ]
Test is a simple but powerful comparison utility. For full details, run man teston your system, but here are some usages and typical examples.
Test is most often invoked indirectly via the if andwhile statements. It is also the reason you will comeinto difficulties if you create a program calledtest andtry to run it, as this shell builtin will be called instead of yourprogram!
The syntax for if...then...else... is:
if [ ... ] then # if-code else # else-code fi
Note that fi is if backwards! This is used againlater withcase and esac.
Also, be aware of the syntax - the "if [ ... ]" and the "then" commands must beon different lines. Alternatively, the semicolon ";" can separate them:
if [ ... ]; then # do something fi
You can also use the elif, like this:
if [ something ]; then echo "Something" elif [ something_else ]; then echo "Something else" else echo "None of the above" fi
This will echo "Something" if the [ something ] test succeeds, otherwise it will test[ something_else ], and echo "Something else" if that succeeds. If all else fails, it will echo "None of the above".
Try the following code snippet, before running it set the variable X to various values (try -1, 0, 1, hello, bye, etc). You can do this as follows (thanks to Dave for pointing out the need to export the variable, as noted inVariables - Part I.):
$ X=5 $ export X $ ./test.sh ... output of test.sh ... $ X=hello $ ./test.sh ... output of test.sh ... $ X=test.sh $ ./test.sh ... output of test.sh ...
Then try it again, with $X as the name of an existing file, suchas/etc/hosts.
test.sh
#!/bin/sh if [ "$X" -lt "0" ] then echo "X is less than zero" fi if [ "$X" -gt "0" ]; then echo "X is more than zero" fi [ "$X" -le "0" ] && \ echo "X is less than or equal to zero" [ "$X" -ge "0" ] && \ echo "X is more than or equal to zero" [ "$X" = "0" ] && \ echo "X is the string or number \"0\"" [ "$X" = "hello" ] && \ echo "X matches the string \"hello\"" [ "$X" != "hello" ] && \ echo "X is not the string \"hello\"" [ -n "$X" ] && \ echo "X is of nonzero length" [ -f "$X" ] && \ echo "X is the path of a real file" || \ echo "No such file: $X" [ -x "$X" ] && \ echo "X is the path of an executable file" [ "$X" -nt "/etc/passwd" ] && \ echo "X is a file which is newer than /etc/passwd"
Note that we can use the semicolon (;) to join two lines together. Thisis often done to save a bit of space in simpleif statements.The backslash simply tells the shell that this is not the end of the line,but the two (or more) lines should be treated as one. This is usefulfor readability. It is customary to indent the following line.
As we see from these examples, test can perform many tests on numbers, strings, and filenames.
Thanks to Aaron for pointing out that -a, -e (both meaning "file exists"),-S (file is a Socket), -nt (file is newer than), -ot (file is older than),-ef (paths refer to the same file) and-O (file is owned my user), are not available in the traditional Bourne shell (eg, /bin/sh on Solaris, AIX, HPUX, etc).
There is a simpler way of writing if statements: The && and|| commands give code to run if the result is true.
#!/bin/sh [ $X -ne 0 ] && echo "X isn't zero" || echo "X is zero" [ -f $X ] && echo "X is a file" || echo "X is not a file" [ -n $X ] && echo "X is of non-zero length" || \ echo "X is of zero length"
This syntax is possible because there is a file (or shell-builtin) called [ which is linked to test. Be careful using thisconstruct, though, as overuse can lead to very hard-to-read code. Theif...then...else... structure is much more readable. Use of the[...] construct is recommended for while loops and trivial sanitychecks with which you do not want to overly distract the reader.
Note that when you set X to a non-numeric value, the first few comparisonsresult in the message:
test.sh: [: integer expression expected before -lt test.sh: [: integer expression expected before -gt test.sh: [: integer expression expected before -le test.sh: [: integer expression expected before -geThis is because the -lt, -gt, -le, -ge, comparisons are only designed for integers, anddo not work on strings. The string comparisons, such as
!= will happily treat"5" as a string, but there is no sensible way of treating "Hello" as aninteger, so the integer comparisons complain.
If you want your shell script to behave more gracefully, you will have to check the contentsof the variable before you test it - maybe something like this:
echo -en "Please guess the magic number: " read X echo $X | grep "[^0-9]" > /dev/null 2>&1 if [ "$?" -eq "0" ]; then # If the grep found something other than 0-9 # then it's not an integer. echo "Sorry, wanted a number" else # The grep found only 0-9, so it's an integer. # We can safely do a test on it. if [ "$X" == "7" ]; then echo "You entered the magic number!" fi fi
In this way you can echo a more meaningfulmessage to the user, and exit gracefully. The$? variable is explainedin Variables - Part II, and grep isa complicated beast, so here goes:grep [0-9] finds lines of text which contain digits (0-9) and possibly other characters, so the caret (^) ingrep [^0-9] finds only those lines which don't consist only of numbers. We can then take the opposite (by acting on failure, not success). Okay? The>/dev/null 2>&1 directs anyoutput or errors to the special "null" device, instead of going to the user's screen.
Many thanks to Paul Schermerhorn for correcting me - this page used to claim thatgrep -v [0-9] would work, but this is clearly far too simplistic.
We can use test in while loops as follows:
test2.sh
#!/bin/sh X=0 while [ -n "$X" ] do echo "Enter some text (RETURN to quit)" read X echo "You said: $X" done
This code will keep asking for input until you hit RETURN (X is zero length).Thanks to Justin Heath for pointing out that the script didn't work - I'd missed out the quotes around $X in thewhile [ -n "$X" ]. Without those quotes, there is nothing to test when $X is empty.
Alexander Weber has pointed out that running this script will end untidily:
$ ./test2.sh Enter some text (RETURN to quit) fred You said: fred Enter some text (RETURN to quit) wilma You said: wilma Enter some text (RETURN to quit) You said: $
This can be tidied up with another test within the loop:
#!/bin/sh X=0 while [ -n "$X" ] do echo "Enter some text (RETURN to quit)" read X if [ -n "$X" ]; then echo "You said: $X" fi done
Note also that I've used two different syntaxes for if statements on this page. These are:
if [ "$X" -lt "0" ] then echo "X is less than zero" fi .......... and ........ if [ ! -n "$X" ]; then echo "You said: $X" fi
You must have a break between the if statement and the then construct. This can be a semicolon ora newline, it doesn't matter which, but there must be one or the other between theif and the then.It would be nice to just say:
if [ ! -n "$X" ] echo "You said: $X"
but the then and fi are absolutely required.
本文详细介绍了Shell脚本中测试命令的使用,包括其基本概念、内置函数、操作符及其语法。通过实例演示了如何在if、while等语句中灵活运用测试命令进行条件判断,同时强调了正确使用操作符的重要性以及一些常见的陷阱。文章还提供了检查变量类型和长度的方法,并展示了如何在循环中高效地读取输入。

被折叠的 条评论
为什么被折叠?



