What is wrong with this code?
if (( `date +%U` % 2 -eq 0 ))
then
VOLUME= "A"
else
VOLUME="B"
fi
I´m getting «syntax error in expression (error token is «0 «)» eror.
tripleee
170k31 gold badges261 silver badges305 bronze badges
asked Dec 12, 2013 at 20:05
2
You need to use command substitution using $(...)
syntax.
You can use this command:
(( $(date +%U) % 2 == 0 )) && VOLUME="A" || VOLUME="B"
answered Dec 12, 2013 at 20:09
anubhavaanubhava
748k64 gold badges550 silver badges622 bronze badges
4
Try this.
case $(date +%U) in
*[02468] ) VOLUME="A";;
*) VOLUME="B";;
esac
Note also that spaces around =
are not permitted.
answered Dec 12, 2013 at 20:12
tripleeetripleee
170k31 gold badges261 silver badges305 bronze badges
I want to start a particular set of services (in the example below, the service is called users), and in my script, that is working. However, I see the following error when running the command:
./services.sh: line 40: [[: start users: syntax error in expression (error token is "users")
I am calling this command using a case
statement in my script, that looks for the start
parameter:
case "$1" in
(-h)
display_help
exit 0
;;
(start)
start_services "$@"
;;
My function for start_services
is as follows:
start_services()
{
# Check to see if there are any arguments, if not, start all services
if [[ $@ -eq 0 ]]; then
echo
echo "Starting all services:"
echo "======================"
for svc in $services
do
echo " Starting the $svc service... "
$SVCPATH/bin/$svc &
done
else
shift;
echo
for var in "$@"
do
echo "Starting the $var service... "
$SVCPATH/bin/$var & > /dev/null
done
fi
}
So, the failure is occurring at this line, line 40:
if [[ $@ -eq 0 ]]; then
As I mentioned, the script is doing what I want, but I keep getting the syntax expression error.
Any ideas as to why this may be happening? Thanks in advance!
I am getting this really weird error despite of the fact that the same script runs fine on one platform (Arch linux) but not on my other mobile platform (Maemo Linux). I’ll pass here the relevant part of the code with the line numbering:
41 for DIR in $DIRS
42 do
43 tempdir=$DIR/
44 tempval=$(stat -c %Y $tempdir)
45 echo $tempval
46 if (( $tempval > $(date +%s) - 3600*24*30 )); then
47 echo "I am done basically. Exiting..."
48 exit
49 else
50 continue
51 fi
52 done
In the code above DIRS is a list which contains names of directories. In this loop i am trying to find one directory of the list which is newer than 30 days old and if i find one i exit the script.
Line 45 is put there for debugging purposes basically.
I am getting the error below:
./script.sh : line 52 : 1372757584 : not found
After some changes suggested from the comments:
Ok the error now is below:
scone.sh: line 46: ((: 1372768246 -gt 1372770593 - 3600*24*30 : syntax error
in expression (error token is "1372770593 - 3600*24*30 ")
I am running into an issue that I can’t quite figure out. I have a BASH script which recurses through directories and compares the current date to the file-modified time of the file. If it is beyond a certain age, the file gets gzipped.
I am receiving the following error:
./serversync.sh: line 87: 1324308130-1323116622
1323581504: syntax error in expression (error token is "1323581504")
The section of code that is running at this point is cited below:
#If the file doesn't have a matching .gz file, compress it
do if [ ! -e ${FILE}.gz ]
then
echo "Matching Gzip doesn't exist for $FILE"
echo Checking to see if compression needed
#test to make sure that the file is 30 days old, and if it is, gzip
FILEMTIME=$(stat -c %Y $FILE)
FILEAGE=$(($DATE-$FILEMTIME))
echo fileage is $FILEAGE
if [ $FILEAGE -gt $COMPRESSWINDOWSTART -a $FILEAGE -lt $COMPRESSWINDOWEND ]
then
echo $FILEAGE is greater than $COMPRESSWINDOWSTART and less than $COMPRESSWINDOWEND
echo Compressing $FILE
gzip $FILE
fi
fi
Line 87 is this line:
FILEAGE=$(($DATE-$FILEMTIME))
If anyone can offer any ideas on why this happens id apprciate it!
15.4. Probable Causes for Syntax Errors
15.4.1 Undefined and Misspelled Variables
As you know, the shells do not require variables to be declared. When a variable name is used in a program, the variable is created automatically. Although this may seem more convenient than having to declare every variable explicitly, there is an unfortunate consequence: An inadvertent spelling error might introduce an extra variable that you had no intention of creating. And because UNIX/Linux is case sensitive, even changing from uppercase to lowercase can cause a program to fail.
When setting a variable in the C/TC shells, the set command is used, and the = sign must be surrounded with space (or no space at all). The set command in bash, sh, and ksh is used to set shell options or create positional parameters, but is not used to define variables. Space is not allowed on either side of the = sign. When switching from one shell to another, it is easy to forget when to use set and when to use or not use spaces.
The C and TC shells will tell you when you are using an undefined variable. The Bourne, Bash, and Korn shells display a blank line, unless you request error checking with the set �u or the shell’s �u invocation option. The �u option flags any variables that have not been defined, called unbound variables.
In the Bourne, Korn, and Bash shells, a variable is set as follows:
x=5
name=John
friend="John Doe"
empty= or empty=""
To check for undefined variables:
set -u
echo "Hi $firstname"
(Output)
ksh: firstname: parameter not set
In the C and TC shells:
set x = 5 set name = John set friend = "John Doe" set empty = ""
The shell checks for undefined variables:
echo "Hi $firstname"
(Output)
firstname: Undefined variable
Example 15.7.
#!/bin/tcsh
1 set friend1 = "George"
set friend2 = "Jake"
set friend4 = "Danny"
2 echo "Welcome $friend3 "
(Output)
3 friend3: Undefined variable.
EXPLANATION
-
Three variables are set. When variables are so similar in thier names, it is easy to mistype one of them later in the program.
-
The variable friend3 was never defined.
-
The C and TC shells send an error to let you know that you have an undefined variable. The Bourne, Korn, and Bash shells leave a blank line.
15.4.2 Incomplete Programming Statements
Missing Keywords
When using a programming statement such as an if statement or while loop, you may accidentally omit part of the statement. For example, you may forget to complete your while loop with the done keyword. Whenever you see an error message concerning unexpected end of file, or if the message points to the line number one past the last (e.g., your script contains 10 lines and the error message refers to line 11), you should check for incomplete programming statements.
Indentation
An easy way to ensure that if/else, while/do/done, case statements, and other contructs are complete is to indent the block of statements under each test expression (at least one tab stop), and move the terminating keyword (done, end, endsw, etc.) to line up with the conditional or looping command that it terminates. This is an extremely helpful technique when these constructs are nested.
if/endif Errors
See the following format for the correct way to set up your if/endif construct with tab stops.
FORMAT
In Bourne, Korn, and Bash shells:
# Without indentation if [ $ch = "a" ] # Use indentation then echo $ch if [ $ch = "b" ] <-- Missing 'then' echo $ch else echo $ch fi <-- Missing 'fi' for first 'if' --------------------------Fix-------------------------- # With indentation if [ $ch = "a" ] then echo $ch if [ $ch = "b" ] then echo $ch else # 'else' goes with nearest 'if' echo $ch fi fi
In C and TC shells:
if ( $ch == "a" ) <-- Missing 'then' echo $ch if ( $ch == "b" ) then echo $ch else echo $ch endif <-- Missing 'endif' for first 'if' --------------------------Fix-------------------------- if ( $ch == "a" ) then echo $ch if ( $ch == "b" ) then echo $ch else echo $ch endif endif
case and switch Errors
There are a number of bugs often found in case and switch commands. The variable that is being tested should be in double quotes if the variable value consists of more than one word. Relational, logical, and equality operators are not allowed in the case constants.
FORMAT
Case statements for the Bourne, Korn, and Bash shells:
case $color in <-- Variable should be quoted blue) statements statements <-- Missing ;; red || orange) <-- Logical || not allowed statements ;; *) statements ;; <-- Missing esac -----------------------The Fix-------------------------------- case "$color" in blue ) statement statement ;; red | orange ) statements ;; *) statements ;; esac
Switch statements for C and TC shells:
switch ($color) <-- Variable should be quoted case blue: statements statements <-- Missing breaksw case red || orange: <-- Logical operator not allowed statements breaksw default: statements breaksw <-- Missing endsw -----------------------The Fix-------------------------------- switch ("$color") case blue: statements statements breaksw case red: case orange: statements breaksw default: statements breaksw endsw
Looping Errors
A looping error occurs when the syntax of a for, foreach, while, or until loop is incorrect, most commonly when one of the keywords used to terminate the looping block is omitted, such as do, done, or end.
FORMAT
Bourne shell:
while [ $n -lt 10 ] <-- Missing do keyword echo $n n=`expr $n + 1` done while [ $n -lt 10 ] do echo $n n=`expr $n + 1` <-- Missing done keyword -----------------------The Fix-------------------------------- while [ $n -lt 10 ] do echo $n n=`expr $n + 1` done
Loops for Bash and Korn shells:
while (( $n <= 10 )) <-- Missing do keyword echo $n (( n+=1 )) done while (( $n <= 10 )) do echo $n (( n+=1 )) <-- Missing done keyword -----------------------The Fix-------------------------------- while (( $n <= 10 )) do echo $n (( n+=1 )) done
Loops for the C and TC shells:
while ( $n <= 10 ) echo $n @n+=1 <-- Missing space after the @ symbol <-- Missing end keyword foreach ( a b c ) <-- Missing variable after foreach echo $char end -----------------------The Fix-------------------------------- while ( $n <= 10 ) echo $n @ n+=1 end foreach char ( a b c ) echo $char end
Operator Errors
The shells use different operators for manipulating strings and numbers. The Bourne shell uses the test command (see man test) and its operators for comparing numbers and strings. Although these operators will work with Korn and Bash shells, normally they are not used. Instead, the Korn and Bash shells provide a set of C-like operators to handle arithmetic with the let command (( )) and string operators to be used with the new test command [[ ]]. But the Korn shell does not use the double == sign for equality, whereas the Bash shell does.
The C and TC shells also provide a set of C-like operators for comparing numbers and strings, and use the == for both numbers and strings. Confusing? If you are porting shell scripts, it might be a good idea to check the operators for each shell. They are provided in tables for each shell in this book. (See Appendix B.) The following examples illustrate some of the operators for each shell.
FORMAT
Bourne shell:
Numeric testing if [ $n -lt 10 ] if [ $n -gt $y ] if [ $n -eq 6 ] if [ $n -ne 6 String testing if [ "$name" = "John" ] if [ "$name" != "John" ]
Korn shell:
Numeric testing if (( n < 10 )) if (( n > y )) if (( n == 6 )) if (( n != 6 )) String testing if [[ $name = "John" ]] if [[ $name != "John" ]]
Bash shell:
Numeric testing if (( n < 10 )) if (( n > y )) if (( n == 6 )) if (( n != 6 )) String testing if [[ $n == "John" ]] if [[ $n != "John" ]]
C and TC shells:
Numeric testing if ( $n < 10 ) if ( $n > $y ) if ( n == 6 )) if ( n != 6 ) String testing if ( "$name" == "John" ) if ( "$name" != "John" )
Misusing an Operator
The following examples illustrate the most common causes of misused operators.
Example 15.8.
(sh) 1 n=5; name="Tom" 2 if [ $n > 0 ] # Should be: if [ $n -gt 0 ] then 3 if [ $n == 5 ] # Should be: if [ $n -eq 5 ] then 4 n++ # Should be: n=`expr $n + 1` 5 if [ "$name" == "Tom" ] # Should be: if [ $name = "Tom" ] (csh/tcsh) set n = 5; set name = "Tom" 6 if ( $n =< 5 ) then # Should be: if ( $n <= 5 ) then 7 if ( $n == 5 && < 6 ) then # Should be: if ( $n == 5 && $n < 6) 8 if ( $name == [Tt]om ) then # Should be: if ($name =~ [Tt]om ) (ksh) name="Tom" n=5 9 if [ $name == [Tt]om ] # Should be: if [[ $name == [Tt]om ]][a] 10 [[ n+=5 ]] # Should be: (( n+=5 ))
EXPLANATION
-
In the Bourne shell, the variable n is assigned 5.
-
The [ bracket is a symbol for the test command. The test command does not use > for greater than, but instead, uses �gt for the relational operator.
-
The double equal sign is not a valid equality operator for the test command. The operator that should be used is �eq.
-
The Bourne shell does not support arithmetic operations.
-
The test command does not use == for equality testing; it uses a single = for string testing and �eq for numeric testing.
-
The csh/tcsh relational operator should be <=. Misusing relational operators causes a syntax error in all shells.
-
The expression on the right-hand side of the logical && is incomplete.
-
The csh/tcsh shells use =~ when evaluating strings containing wildcards. The error in this example would be No match.
-
The single bracket type of testing does not support the == sign. Bash and ksh use the [[ test command to test expressions containing wildcards. The double equal sign, rather than the single equal sign, is used for testing string equality. (Only versions of ksh newer than ksh88 support the == sign. Earlier versions require the single = for string testing.)
-
The [[ test command is used with string expressions; the (( let command is used for numeric expressions.
Quoting Errors
Misused quotes are such a common cause for error in shell scripts that a whole section has been devoted to quoting. (See «What You Should Know About Quotes» on page 985.) Quotes are often called the «bane of shell programmers» or the «quotes from hell.» There are three types of quotes: single quotes, double quotes, and backquotes. Single and double quotes surround strings of text to protect certain characters from interpretation, whereas backquotes are used for command substitution. Although we have discussed quotes in previous chapters, the next few sections will focus on how to use them properly to avoid errors.
Quoting Metacharacters
A problem directly related to quoting is the misuse of metacharacters. We’ve already discussed two kinds of metacharacters: shell metacharacters and regular expression metacharacters used with vi, grep, sed, awk, and utility programs other than the shell. (See Chapter 3, «Regular Expressions and Pattern Matching,» on page 67.) Unquoted metacharacters will be interpreted by the shell to mean file matching, and unquoted regular expression metacharacters may cause programs like grep, sed, and nawk to break down. In the following example, the * is used by grep to represent zero or more of the letter «b» and the * is used by the shell to match all filenames starting with an «f». The shell always evaluates the command line before executing the command. Because grep’s * is not quoted, the shell will try to evaluate it, causing an error.
grep ab*c f*
To fix the problem, quotes are used:
grep 'ab*c' f*
Now when the shell parses the command line, it will not evaluate the characters within the quotes.
Quotes must be matched. Most shells will send an error message when they realize that there are unmatched quotes. The Bourne shell, on the other hand, parses an entire script file before reporting a problem, which is usually «unexpected end of file,» hardly a big help when the same error message is displayed for a number of other problems.
In order to really achieve expertise in shell scripting, it is imperative to get a good understanding of the quoting mechanism.
Example 15.9.
#! /bin/csh 1 echo I don't understand you. # Unmatched single quote (Output) 2 Unmatched ' ---------------------------------------- #! /bin/csh 3 echo Gotta light? # Unprotected wildcard (Output) 4 echo: No match ---------------------------------- #!/bin/csh 5 set name = "Steve" 6 echo 'Hello $name.' # Variable not interpreted (Output) Hello $name
EXPLANATION
-
Quotes must be matched. The single quote in don’t causes an error. To fix the problem, the string can be enclosed in double quotes or the single quote can be preceded by a backslash, as don’t.
-
The C shell displays its error message for a mismatched single quote.
-
The shell metacharacter, ?, is used to match for single character filenames. There is not a file in the directory spelled light and followed by a single character.
-
The C shell complains that there is No match for that metacharacter. To fix the problem, the string should be enclosed in either single or double quotes or the question mark should be preceded by a backslash, as ‘Gotta light?’ or light?
-
The string «Steve» is assigned to a variable.
-
The string is enclosed in single quotes. The characters within the single quotes are treated literally (i.e., the variable will not be interpreted). To fix the problem, the string should be enclosed in double qutoes or no quotes at all, as «Hello $name.»
What You Should Know About Quotes
Quotes are so inherently part of shell scripting that this section is provided to clarify their use in all the shells. If you are regularly getting quoting syntax errors, study this section to be sure you know how to use them, especially if your script contains commands like grep, sed, and awk.
The Backslash
-
Precedes a character and escapes that character
-
Same as putting single quotes around one character
Single Quotes
-
Must be matched
-
Protect all metacharacters from interpretation except the following:
-
Itself
-
Exclamation point (csh only)
-
Backslash
-
C/TC Shells |
Bourne/Bash Shells |
Korn Shell |
|
---|---|---|---|
echo '$*&><?'
$*&><?
|
echo '$*&!><?'
$*&!><?
|
print '$*&!><?'
$*&!><?
|
|
(C) |
echo 'I need $5.00!'
I need $5.00!
|
echo 'I need $5.00!'
I need $5.00!
|
print ‘I need $5.00!’ |
(TC)’ |
echo ‘I need $5.00! |
||
echo 'She cried, "Help"'
She cried, "Help"
|
echo 'She cried,"Help"'
She cried, "Help"
|
print 'She cried, "Help"'
She cried, "Help"
|
|
echo ‘\\’ |
echo ‘\\’ |
print ‘\\’ |
|
\\ |
(Bourne) \ (Bash) \\ |
\ |
Double Quotes
-
Must be matched
-
Protect all metacharacters from interpretation except the following:
-
Itself
-
Exclamation point (csh only)
-
$ used for variable substitution
-
` ` Backquotes for command substitution
-
C Shell |
Bourne Shell |
Korn Shell |
---|---|---|
echo «Hello $LOGNAME!» |
echo «Hello $LOGNAME!» |
print «Hello $LOGNAME!» |
echo «I don’t care» |
echo «I don’t care» |
print «I don’t care» |
echo «The date is ‘date'» |
echo «The date is ‘date'» |
print «The date is $(date)» |
echo «\\» |
echo «\\» |
print «\\» |
\\ |
Backquotes
Backquotes are used in shell programs for command substitution. They are unrelated to single and double quotes, but often the source of problems. For example, when copying a shell script, if the backquotes are replaced with single quotes (merely by misreading the code), the program will no longer work.[1]
[1] In the production of this type of book, it is very easy to mistake backquotes for single quotes!
Example 15.10.
#!/bin/sh 1 now=`date` 2 echo Today is $now 3 echo "You have `ls|wc -l` files in this directory" 4 echo 'You have `ls|wc -l` files in this directory' (Output) 2 Today is Mon Jul 5 10:24:06 PST 2004 3 You have 33 files in this directory 4 You have `ls|wc -l` files in this directory
EXPLANATION
-
The variable now is assigned to the output of the UNIX/Linux date command. (For the T/TC shell: set now = `date`.) The backquotes cause command substitution. The backquote is normally found under the tilde (~) on your keyboard.
-
The value of variable now is displayed with the current date.
-
The backquotes surround a UNIX/Linux pipe. The output of ls is piped to wc �l. The result is to count the number of files listed in this directory. Double quotes around the string will not interfere with command substitution. The output is embedded in the string and printed.
-
By enclosing the string in single quotes, the backquotes are not interpreted, but treated as literal characters.
Combining Quotes
Combining quotes can be a major trick. This next section will guide you through the steps for successfull quoting. We will demonstrate how to embed a shell variable in the awk command line and have the shell expand the variable without interfering with awk’s field designators, $1 and $2.
Setting the Shell Variable
name="Jacob Savage" (Bourne and Korn shells) set name = "Jacob Savage" (C shell) (The line from the datafile) Jacob Savage:408-298-7732:934 La Barbara Dr. , San Jose, CA:02/27/78:500000 (The nawk command line) nawk -F: '$1 ~ /^'"$name"'/{print $2}' datafile (Output) 408-298-7732
Try this example:
-
Test your knowledge of the UNIX/Linux command at the command line before plugging in any shell variables.
nawk -F: '$1 ~ /^Jacob Savage/{print $2}' filename (Output) 408-298-7732
-
Plug in the shell variable without changing anything else. Leave all quotes as they were.
nawk -F: '$1 ~ /^$name/{print $2}' datafile
Starting at the left-hand side of the awk command leave the first quote as is; right before the shell dollar sign in $name, place another single quote. Now the first quote is matched and all text within these two quotes is protected from shell interference. The variable is exposed. Now put another single quote right after the e in $name. This starts another matched set of single quotes ending after awk’s closing curly brace. Everything within this set of quotes is also protected from shell interpretation.
-
Enclose the shell variable in a set of double quotes. This allows the variable to be expanded but the value of the variable will be treated as single string if it contains whitespace. The whitespace must be protected so that the command line is parsed properly.
Count the number of quotes. There should be an even number of single quotes and an even number of double quotes.
Here’s another example:
oldname="Ellie Main" newname="Eleanor Quigley"
-
Make sure the command works.
nawk -F: '/^Ellie Main/{$1="Eleanor Quigley"; print $0}' datafile
-
Plug in the variables.
nawk -F: '/^$oldname/{$1="$newname"; print $0}' datafile
-
Play the quoting game. Starting at the first single quote at the left, move across the line until you come to the variable $oldname and place another single quote just before the dollar sign. Put another single quote right after the last letter in the variable name.
Now move to the right and place another single quote right before the dollar sign in $newname. Put another single quote after the last character in $newname.
-
Count the number of single quotes. If the number of single quotes is an even number, each quote has a matching quote. If not, you have forgotten a step.
-
Enclose each of the shell variables in double quotes. The double quotes are placed snugly around the shell variable.
Problems with the here document
The here document, used primarily for creating menus in shell scripts, is often a source of error. The problem is usually found with the user-defined terminator that ends the here document. There can be no space around the terminator. All shells are strict about this rule, although the Bourne, Bash, and Korn shells allow you to use tabs under certain conditions. See the following example.
Example 15.11.
#! /bin/ksh print "Do you want to see the menu?" read answer if [[ $answer = y ]] then 1 cat << EOF <-- No space after user-defined terminator 1) Steak and eggs 2) Fruit and yogurt 3) Pie and icecream 2 EOF <-- User-defined terminator cannot have spaces surrounding it print "Pick one " read choice case "$choice" in 1) print "Cholesterol" ;; 2) print "Dieter" ;; 3) print "Sweet tooth" ;; esac else print "Later alligator!" fi (Output) file: line 6: here document 'EOF' unclosed or file: line 6: syntax error: unexpected end of file (bash)
EXPLANATION
-
This is the start of a here document. The cat command is followed by << and a user-defined terminator, in this case, EOF. The lines following the terminator are used as input to the cat command, producing a menu of choices on the screen. The input stops when the terminator is reached on line 2.
-
The terminator on line 2 must exactly match the one on line 1 or the here document will not end. In addition, the final terminator cannot be surrounded by any space. The well-meaning programmer tried to indent the script for better readability, but, in this case indenting the EOF on line 2 causes a syntax error. The solution is to move the terminating EOF to the far left-hand margin and make sure there is no space surrounding it. The bash/ksh/sh shells allow one other fix, which is to put a dash after the << symbol: cat <<� EOF . This allows you to use tabs (and only tabs) to indent the final terminator on line 2.
File-Testing Errors
If you are using external files in a script, it is best to check certain properties of the files before using them, such as their existence, whether they are readable or writable, have any data, are a symbolic link, and so forth. The file tests are quite similar for each shell, but the test for file existence varies. For example, the C, TC, and Bash shells use the �e switch to check if a file exists, the Korn shell uses the �a switch, and the Bourne shell uses the �f switch. With the exception of the TC shell, the file-testing switches cannot be bound together, such as �rw for read and write. Instead a single file-testing switch precedes the filename. An example of a C shell test for a readable, writable, and executable file would be if (�r filename && �w filename && �x filename). An example for a TC shell test would be if (�rwx filename).
Checking for File Existence in the Five Shells
The following error message was generated before file testing was performed in a script. The file called db did not exist.
grep: db: cannot open [No such file or directory]
The following example demonstrates how to fix this problem for each of the five shells.
Example 15.12.
(csh/tcsh) set filedb = db if ( ! -e $filedb ) then echo "$filedb does not exist" exit 1 endif (sh) filedb=db if [ ! -f $filedb ] then echo "$filedb does not exist" exit 1 fi (ksh) filedb=db if [[ ! -a $filedb ]] then print "$filedb does not exist" exit 1 fi (bash) filedb=db if [[ ! -e $filedb ]] then echo "$filedb does not exist" exit 1 fi
15.4.3 Common Error Messages from the Big 5 Shells
There are a number of different types of syntax errors that will be reported by the shell when you run a script. Each shell reports these errors by sending a message to standard error, and the messages vary from shell to shell. The C shell, for example, is very verbose, and reports errors such as unmatched quotes and undefined variables on the same line where the error occurred, whereas the Bourne shell error messages are sparse and quite cryptic. It is often very hard to debug a Bourne shell script because the error is not reported at all until the script has been completely parsed, and when you get the error message, it may not tell you anything to help you understand your erring ways.
Because each of the shells has its own style of error reporting, Tables 15.3 through 15.6 illustrate the most common syntax errors, the probable cause, what the error message means, and a simple fix.
Error Message |
What Caused It |
What It Means |
How to Fix It |
---|---|---|---|
«: Event not found. |
echo «Wow!» |
The exclamation mark (history character) must be escaped. Quotes will not protect it. |
echo «Wow!» |
@: Badly formed number |
set n = 5.6; @ n++; @ n = 3+4 |
Arithmetic can be performed only on whole numbers and there must be space surrounding arithmetic operators. |
set n = 5; @ n++; @ n = 3 + 4 |
@n++: Command not found |
@n++ |
The @ sign must be followed by a space. |
@ n++ |
Ambiguous. |
`date` |
The backquotes are used for command substitution when the output of a command is being assigned to a variable or is part of a string. If the command is on a line by itself, it should not be enclosed in backquotes. Tcsh will give the error Fri: Command not found. |
echo The date is `date` or set d = `date` |
Bad : modifier in $ (f). |
echo $cwd:f |
The :f is an invalid pathname expansion modifier. |
echo $cwd:t or $cwd:h etc. |
Badly placed ()’s. |
echo (abc) |
The parentheses are used to start a subshell. The whole command should be placed in () or the string should be quoted. |
( echo abc ) or echo «(abc)» |
echo: No match. |
echo How are you? |
The question mark is a shell metacharacter used in filename expansion. It represents one character in a filename. The shell will match for a file named you followed by a single character. Because there isn’t a file by that name, the error No match is displayed. |
echo "How are you?" or echo 'How are you?' or echo How are you? |
filex: File exists. |
sort filex > temp |
The noclobber variable has been set and the temp file exists. noclobber will not let you overwrite an existing file. |
sort filex > temp1 (use a different file for output) or unset noclobber or sort filex >! temp (override noclobber) |
fruit: Subscript out of range |
echo $fruit[3] |
The array fruit does not have three elements. |
set fruit = ( apples pears plums ) |
if : Empty if |
if ( $x > $y ) |
The if expression is incomplete. The then is missing. |
if ( $x > $y ) then |
if : Expression Syntax |
if ( $x = $y ) then |
The if equality operator should be ==. |
if ( $x == $y ) then |
if : Expression Syntax |
set name = "Joe Doe" if ( $name == "Joe Doe" ) then |
The variable name on the left-hand side of the == sign should be double quoted. |
if ( «$name» == «Joe Doe» ) then |
if: Expression syntax. |
if ( grep john filex ) then |
When evaluating a command, curly braces should surround the command, not parentheses. |
if { grep john filex } then |
Invalid null command |
echo «hi» &> temp |
The redirection operator is backwards. Should be >&. |
echo «hi» >& temp |
Missing }. |
if {grep john filex} then |
The curly braces must be surrounded by space. |
if { grep john filex } then |
set: Syntax error |
set name= «Tom» |
The equal sign must have space on either side, or no space at all. |
set name = «Tom» or set name=»Tom» |
set: Syntax error |
set name.1 = «Tom» |
A period is not a valid character in a variable name. |
set name1 = «Tom» |
set: Syntax error |
set file-text = «foo1» |
The dash is an illegal character in the variable name. |
set file_text = «foo1» |
shift: No more words |
shift fruit |
The shift command removes the leftmost word in an array. The error is caused because the array, fruit, has no more word elements. You cannot shift an empty array. |
set fruit = ( apples pears plums ) |
then: then/endif not found. |
if ( $x > $y ) then statements statements |
The if expression is incomplete. The endif is missing. |
if ( $x > $y ) then statements endif |
Too many (‘s |
if ( $x == $y && ( $x != 3 ) then |
The expression has unbalanced parentheses. Either add one to the right-hand side or remove the ( after the &&. |
if ( $x == $y && ( $x != 3 )) then or if ( $x == $y && $x != 3 ) then |
top: label not found. |
goto top |
The goto command is looking for a label called top that should be on a line by itself somewhere in the program. Either that, or the label is there but is spelled differently. |
top: goto top |
Undefined variable |
echo $name |
The variable name has never been set. |
set name; set name = "John"; set name = "" |
Unmatched «. |
echo She said, «Hello |
The double quote must be matched on the same line. |
echo ‘She said, «Hello»‘ |
Unmatched ‘. |
echo I don’t care |
The single quote must be matched on the same line. |
echo «I don’t care» or echo I don’t care |
while: Expression syntax. |
while ( $n =< 5 ) |
The wrong operator was used. It should be <=. |
while ( $n <= 5 ) |
Error Message |
What Caused It |
What It Means |
How to Fix It |
---|---|---|---|
bash: syntax error: ‘» unexpected EOF while looking for matching ‘» |
echo I don’t care |
The single quote is unmatched in the script. |
echo «I don’t care» |
bash: syntax error: ‘»‘ unexpected EOF while looking for matching ‘» |
print She said «Hello |
The double quote is unmatched in the script. |
print She said «Hello» |
[Blank line] No error message, no output |
echo $name or echo ${fruit[5]} |
The variable doesn’t exist or is empty. |
name=»some value» or use set -u to catch any variables that have not been sent. The message ksh: name: paramter not set will be sent to stderr. |
bash: name: command not found |
name = «Tom» |
There cannot be any space on either side of the equal sign. |
name=»Tom» |
bash: 6.5: syntax error in expression (error token is «.5») |
declare -i num; num=6.5 |
Only integer values can be assigned to variable num. |
num=6 |
bash: [ellie: command not found |
if [$USER = «ellie»] ; then or if [[$USER = «ellie» ]] ; then |
There must be a space after the [ or [[. |
if [ $USER = «ellie» ] ; then or if [[ $USER = «ellie» ]] ; then |
bash: syntax error near unexpected token ‘fi’ |
if [ $USER = «ellie» ] then |
The then should be on the next line or preceded by a semicolon. |
if [ $USER = «ellie» ] ; then or if [ $USER = "ellie" ] then |
bash: syntax error in conditional expression |
if [[ $name = John Doe ]] ; then |
Word splitting is not performed on the variable on the left-hand side of the =, but the string on the right-hand side must be quoted. |
if [[ $name == «John Doe» ]] ; then |
[: fred: binary operator expected |
if [ grep fred /etc/passwd ] ; then |
The grep command should not be surrounded by square brackets or any other symbols. The brackets are used only when testing expressions. The [ is a test operator. |
if grep fred /etc/passwd ; then |
./file: line 5: syntax error near unexpected token blue) |
color="blue" case $color |
The case command is missing the in keyword. |
case $color in |
.filename: line2:syntax error at line 6: «)» unexpected. |
case $color in blue) echo "blue" red) echo "red" ;; esac |
The case statement is not terminated with ;; after echo «blue». |
case $color in blue) echo "blue" ;; red) echo "red" ;; esac |
bash: shift: bad non-numeric arg ‘fruit’ |
declare -a fruit=(apples pears peaches); shift fruit |
The shift built-in command cannot shift an array. It is used only to shift positional parameters. |
set apples pears peaches; shift |
[: too many arguments |
name="John Doe"; if [ $name = Joe ] |
The variable name should be double quoted in the test expression. There can be only one string on the left-hand side of the = test operator unless it is quoted. The other alternative is to use the compound test operator [[ ]]. Words will not be split when using this operator. |
if [ «$name» = Joe ] or if [[ $name == Joe ]] |
bash: syntax error near unexpected token ‘{echo’ |
function fun {echo «hi»} |
There should be space surrounding the curly braces in the definition for the function fun() and a semicolon to terminate the function statement. |
function fun { echo «hi»; } |
bash: filex: cannot overwrite existing file |
sort filex > temp |
The noclobber variable has been set and the temp file exists. noclobber will not let you overwrite an existing file. |
sort filex > temp1 (use a different file for output) or set +o noclobber or sort filex >| temp (override noclobber) |
bash: trap: 500: not a signal specification |
trap ‘rm tmp*’ 500 |
The number 500 is an illegal signal. Normally signals 2 or 3 will be trapped in a shell script. 2 is for Ctrl-C and 3 is for Ctrl-. Both signals cause the program named after the trap command to be terminated. |
trap ‘rm tmp*‘ 2 |
Common C/TC Shell Error Messages
Table 15.3 lists commonly found C shell error messages. Because the TC shell mimics the the C shell errors so closely, the chart serves to address both shells.
Common Bourne Shell Error Messages
Table 15.4 lists commonly found Bourne shell error messages.
Error Message |
What Caused It |
What It Means |
How to Fix It |
---|---|---|---|
./file: line 5: syntax error near unexpected token blue) |
color="blue" case $color |
The case command is missing the in keyword. |
case $color in |
[Blank line] The shell produces a blank line, no error message. |
echo $name |
The variable doesn’t exist or is empty. |
name=»some value»; |
[ellie: not found |
if [$USER = «ellie»] ; then |
There must be a space after the [. |
if [ $USER = «ellie» ] ; then |
answer: not found |
answer = «yes» |
There cannot be any space on either side of the equal sign. |
answer=»yes» |
cannot shift |
shift 2 |
The shift built-in command is used to shift positional parameters to the left. If there are not at least two positional parameters, the shift will fail. |
set apples pears peaches; shift 2 (apples and pears will be shifted from the list) |
name: is read only |
name="Tom"; readonly name; name="Dan" |
The variable was set to be a readonly variable. It cannot be redefined or unset. |
name2=»Dan» or exit shell |
name: parameter not set |
echo $name |
set -u has been set. With this option to the set command, undefined variables are flagged. |
name=»some value»; |
name.1=Tom: not found |
name.1=»Tom» |
A period is not valid in a variable name. |
name1=»Tom» |
syntax error at line 7 ‘fi’ unexpected |
if [ $USER = "ellie" ] echo "hi" fi |
There must be then after the expression. |
if [ $USER = "ellie" ] then echo "hi" fi |
syntax error: `{‘ |
fun() {echo «hi»;} |
There should be space surrounding the curly braces in the definition for the function, fun(). |
fun() { echo «hi»; } |
syntax error: ‘done’ unexpected |
while [ $n < 5 ] statements done |
The while is missing the do keyword. |
while [ $n -lt 5 ] do statements done |
syntax error: ‘fi’ unexpected» |
if [ $USER = «ellie ] then |
The then should be on the next line or preceded by a semicolon. |
if [ $USER = "ellie" ] then or if [ $USER = «ellie» ]; then |
test: argument expected |
if [ 25 >= 24 ] ; then |
The >= is not a valid test operator. Should be -ge . |
if [ 25 -ge 24 ]; then |
test: unknown operator |
if [ grep $USER /etc/passwd ] ; then |
The grep command should not be surrounded by square brackets or any other symbols. The brackets are used only when testing expressions. The [ is a test operator. |
if grep $USER /etc/passwd ; then |
test: unknown operator Doe |
name="John Doe"; if [ $name = Joe ] |
The variable, name, should be double quoted in the test expression. There can be only one string on the left-hand side of the = operator unless it is quoted. |
if [ «$name» = Joe ] |
trap: bad trap |
trap ‘rm tmp*’ 500 |
The number 500 is an illegal signal. Normally signals 2 or 3 will be trapped in a shell script. 2 is for Ctrl-C and 3 is for Ctrl-. Both signals cause the program named after the trap command to be terminated. |
trap ‘rm tmp*’ 2 |
unexpected EOF or unexpected end of file |
echo «hi |
The double quote is unmatched in the script. The Bourne shell will search until the end of the file for the matching quote. You may not receive an error message, but program output will be unexpected. The unexpected EOF error will occur if the case or looping commands are not ended with their respective keywords, esac and done. |
echo «hi» |
Common Korn Shell Error Messages
Table 15.5 lists commonly found Korn shell error messages.
Error Message |
What Caused It |
What It Means |
How to Fix It |
---|---|---|---|
./file: line 5: syntax error near unexpected token blue) |
case $color blue) ... |
The case command is missing the in keyword in a script. |
case "$color" in blue) ... |
.filename: line2:syntax error at line 6: «)» unexpected . |
case $color in blue) echo "blue" red) echo "red" ;; esac |
The first case statement is not terminated with ;; after echo «blue». |
case $color in blue) echo "blue" ;; red) echo "red" ;; esac |
[Blank line ] |
echo $name or echo ${fruit[5]} |
The variable doesn’t exist or is empty. |
name=»some value» |
file: line2: syntax error at line 6: ‘done’ unexpected |
while (( $n < 5 )) statements done |
The while is missing the do keyword. |
while (( n < 5 )) do statements done |
file: syntax error at line 3: ‘» unmatched |
print I don’t care |
The single quote is unmatched in the script. It should be preceded by a backslash or enclosed in double quotes. |
echo I don’t care or echo «I don’t care» |
file: syntax error at line 3: ‘»‘ unmatched |
print She said «Hello |
The double quote is unmatched in the script. |
print She said «Hello» |
ksh: [: Doe: unknown operator |
name="John Doe" if [ $name = Joe ]; then |
The variable, name, should be double quoted in the test expression. There can be only one string on the left-hand side of the = test operator unless it is quoted. The other alternative is to use the compound test operator [[ ]]. Words will not be split when using this operator. |
if [ «$name» = Joe ]; then or if [[ $name = Joe ]]; then |
ksh: [ellie: not found |
if [$USER = "ellie"] ; then if [[$USER = "ellie" ]] ; then |
There must be a space after the [ or [[. |
if [ $USER = «ellie» ] ; then or if [[ $USER = «ellie» ]] ; then |
ksh: apples: bad number |
set -A fruit apples pears peaches; shift fruit |
The shift built-in command cannot shift an array. It is used only to shift positional parameters. |
set apples pears peaches; shift |
-ksh: file.txt=foo1: not found |
file.txt=»foo1″ |
The variable cannot have a period in its name. |
file_txt=»foo1″ |
ksh: filex: file already exists. |
sort filex > temp |
The noclobber variable has been set and the temp file exists. noclobber will not let you overwrite an existing file. |
sort filex > temp1 (use a different file for output) or set +o noclobber or sort filex > temp (override noclobber) |
ksh: fred: unknown test operator |
if [ grep fred /etc/passwd ] ; then |
The grep command should not be surrounded by square brackets or any other symbols. The brackets are used only when testing expressions. The [ is a test operator. |
if grep fred /etc/passwd ; then |
ksh: name: not found |
name = «Tom» |
There cannot be any space on either side of the equal sign. |
name=»Tom» |
ksh: shift: bad number |
shift 2 |
The shift built-in command is used to shift positional parameters to the left. If there are not at least two positional parameters, the shift will fail. |
set apples pears peaches; shift 2 (apples and pears will be shifted from the list) |
ksh: syntax error: ‘{echo’ not expected |
function fun {echo «hi»} |
There should be space surrounding the curly braces in the definition for the function fun() and a semicolon to terminate the function statement. |
function fun { echo «hi»; } |
ksh: syntax error: ‘Doe’ unexpected |
if [[ $name = John Doe ]] |
Word splitting is not performed on the variable on the left-hand side of the =, but the string on the right-hand side must be quoted. |
if [[ $name = «John Doe» ]] |
ksh: syntax error: ‘fi’ unexpected» |
if [ $USER = «ellie ] then |
The then should be on the next line or preceded by a semicolon. |
if [ $USER = "ellie" ] then or if [ $USER = «ellie» ] ; then |
ksh: syntax error: ‘then’ unexpected |
if (( n==5 && (n>3 || n<7 )) |
The parentheses enclosing the second expression are not matched. |
if (( n==5 && (n>3 || n<7) )) |
ksh: trap: 500: bad trap [a] |
trap ‘rm tmp*‘ 500 |
The number 500 is an illegal signal. Normally signals 2 or 3 will be trapped in a shell script. 2 is for Ctrl-C and 3 is for Ctrl-. Both signals cause the program named after the trap command to be terminated. |
trap ‘rm tmp*‘ 2 |
[a] This error occurs with public domain Korn shell, but Korn shell 88 (Solaris) produces no output.
Common Bash Error Messages
Table 15.6 lists commonly found Bash shell error messages.
15.4.4 Logic Errors and Robustness
Logic errors are hard to find because they do not necessarily cause an error message to be displayed, but cause the program to behave in an unexpected way. Such errors might be the misuse of a relational, equality, or logical operator, branching incorrectly in a set of nested conditional statements, or going into an infinite loop. Robustness refers to errors that should have been spotted if sufficient error checking had been performed, such as checking for bad user input, insufficient arguments, or null values in variables.
Logical Operator Errors
Example 15.13 shows a logical operator error and a possible fix for it.
Example 15.13.
#!/bin/csh 1 echo -n "Enter -n your grade: " set grade = $< 2 if ( $grade < 0 && $grade > 100 ) then 3 echo Illegal grade. # This line will never be executed exit 1 endif 4 echo "This line will always be executed." (Output) Enter your grade: -44 This line will always be executed. Enter your grade: 234 This line will always be executed. Enter your grade ------------------Possible Fix---------------- if ( $grade < 0 || $grade > 100 ) then
EXPLANATION
-
The user is asked for input. The input is assigned to the variable grade.
-
With the logical AND (&&) both expressions must be true in order to enter the if block on line 3. If both expressions are true, the user would have to have entered a grade that is both lower than 0 and also greater than 100. How could that be possible? The || OR operator should be used. Then only one of the conditions must be true.
-
This line will never be printed.
-
Because line 2 will never be true, this statement will always be executed.
Relational Operator Errors
Example 15.14 shows a relational operator error and a possible fix for it.
Example 15.14.
#!/bin/csh echo -n "Please enter your age " set age = $< 1 if ( $age > 12 && $age < 19 ) then echo A teenager # What if you enter 20? 2 else if ( $age > 20 && $age < 30 ) then echo A young adult 3 else if ( $age >= 30 ) then # What if the user enters 125? echo Moving on in years else 4 echo "Invalid input" endif (Output) Please enter your age 20 Invalid input Please enter your age 125 Moving on in years ------------------Possible Fix---------------- if ( $age > 12 && $age <= 19 ) then echo A teenager else if ( $age >= 20 && $age < 30 ) then echo A young adult else if ( $age >= 30 && $age < 90 ) then echo Moving on in years else if ( $age <=12 ) then echo still a kid else echo "Invalid input" endif
EXPLANATION
-
This expression tests for an age between 13 and 18. To check for ages between 13 and 20, the right-hand expression can be changed in two ways: ( $age <= 19 ) to include 19, or ( $age < 20 ).
-
If the age is 19, the program will always go to line 3. This expression tests for ages between 21 and 29. We need to include 20 in this expression. If the user enters 19 or 20, the program prints Invalid input.
-
This expression tests for any age older than 29. There is no range here. Unless the user can be infinitely old, the expression needs to include the outside range.
-
Invalid inputs are 19, 20, and any number below 13.
Branching Errors
Example 15.15 shows a branching error and a possible fix for it.
Example 15.15.
1 set ch = "c" 2 if ( $ch == "a" ) then 3 echo $ch 4 if ( $ch == "b" ) then # This "if" is never evaluated echo $ch 5 else 6 echo $ch 7 endif 8 endif (Output) <no output> ------------------Possible Fix---------------- set ch = "c" if ( $ch == "a" ) then echo $ch else if ( $ch == "b" ) then echo $ch else echo $ch endif
EXPLANATION
-
The variable ch is assigned the letter c.
-
If the value of $ch is an a, then lines 3 to 5 are executed.
-
If the value of $ch is an a, the value of $ch is printed, and the program continues with the nested if on line 4. This statement will never get executed unless $ch was an a.
-
If the value of $ch were an a, then it could not be a b and line 6 would be executed.
-
This else should be indented so that it is placed under the inner if. The else goes with the innermost if on line 4.
-
This line will be executed only if $ch is an a.
-
This endif goes with the innermost if on line 4.
-
This endif goes with the outer if on line 2.
Exit Status with an if Conditional
When the if command is evaluating the success or failure of a command, it checks the exit status of that command. If the exit status is 0, the command was successful and if nonzero the command failed in some way. If you are not sure of what exit status a command returns, you should check before using it, or your program may not perform as expected. Consider the following example. The awk, sed, and grep commands are all able to use regular expressions for searches in a pattern, but grep is the only one of the three commands that reports a nonzero exit status if it cannot find the search pattern. The sed and awk programs will return 0, whether the pattern is found or not. Therefore, neither of these programs would be of any use after an if condition, because the condition would always be true.
Example 15.16.
#!/bin/sh 1 name="Fred Fardbuckle" 2 if grep "$name" db > /dev/null 2>&1 then 3 echo Found $name else 4 echo "Didn't find $name" # Fred is not in the db file fi 5 if awk "/$name/" db > /dev/null 2>&1 then 6 echo Found $name else echo "Didn't find $name" fi 7 if sed -n "/$name/p" db > /dev/null 2>&1 then 8 echo Found $name else echo "Didn't find $name" fi (Output) 4 grep: Didn't find Fred Fardbuckle 6 awk: Found Fred Fardbuckle 8 sed: Found Fred Fardbuckle ------------------------Possible Fix-------------------------- Check the exit status of the command before using it. awk "/$name/" db echo $? (bash, sh, ksh) echo $status (tcsh, csh, bash)
EXPLANATION
Here we see that awk, nawk, and gawk always return an exit status of 0, unless the command statements are incorrect. grep returns an exit status of 0 if its search is successful, and a nonzero integer if it cannot find the pattern in the file or if the file does not exist.
Lacking Robustness
A program is robust if it can handle illegal input and other unexpected situations in a reasonable way. For example, if a program is expecting numeric data, then it must be able to check to see if that’s what it got, and print an error message and ignore the bad input. Another example of robustness would be if the script is going to extract data from an external file, but the external file doesn’t exist or does not have read permissions. The robust program would use file testing to check for the existence of the file before trying to read from it.
Example 15.17 shows how to check for null input.
Example 15.17.
#!/bin/csh # Program should check for null input -- T and TC shells 1 echo -n "Enter your name: " set name = $< # If user enters nothing, program will hang 2 if { grep "$name" db >& /dev/null } then echo Found name endif (Output) Enter your name: Ellie Found name Enter your name: <program prints every line in the file Found name> ---------------------Possible Fix------------------------------------- echo -n "Enter your name: " set name = $< # If user enters nothing, program will hang 3 while ( $name == "" ) echo "Error: you did not enter anything." echo -n "Please enter your name" set name = $< end <program continues here>
EXPLANATION
-
The user is asked for input. If he or she presses the Enter key, the variable, name, will be set to null.
-
The first time the program runs, the user types something and grep searches in the file for that pattern. The next time, the user presses the Enter key. The variable is set to null, causing the the grep program to search for null. Every line will be printed. Because the errors and output are sent to /dev/null, it is not obvious why the grep is printing the contents of the entire file.
-
The loop tests for a null value in the variable name. The loop will continue until the user enters something other than pressing Enter. For ksh, bash, and sh, use the correct syntax for a while loop (e.g., while [ $name = » » ] or while [[ $name = » » ]). See specific character for syntax.
Examples 15.18 and 15.19 show how to check for insufficient arguments.
Example 15.18.
#!/bin/sh # Script: renames a file -- Bourne shell 1 if [ $# -lt 2 ] # Argument checking 2 then echo "Usage: $0 file1 file2 " 1>&2 exit 1 fi 3 if [ -f $1 ] # Check for file existence then mv $1 $2 # Rename file1 echo $1 has been renamed to $2 else echo "$1 doesn't exist" exit 2 fi (Output) $ ./rename file1 Usage: mytest file1 file2
EXPLANATION
-
If the number of positional parameters (arguments) is less than 2 . . .
-
. . . the error message is sent to standard error and the program exits. The exit status will be 1, indicating a problem with the program.
-
The program continues if sufficient arguments are passed in from the command line. Check correct syntax to convert this program to ksh or bash.
Example 15.19.
#!/bin/csh # Script: renames a file -- C/TC shells 1 if ( $#argv < 2 ) then # Argument checking 2 echo "Usage: $0 file1 file2 " 3 exit 1 endif if ( -e $1 ) then # Check for file existence mv $1 $2 # Rename file1 echo $1 has been renamed to $2 else echo "$1 doesn't exist" exit 2 endif (Output) % ./rename file1 Usage: mytest file1 file2
Examples 15.20 and 15.21 show how to check for numeric input.
Example 15.20.
(The Script) $ cat trap.err #!/bin/ksh # This trap checks for any command that exits with a nonzero # status and then prints the message -- Korn shell 1 trap 'print "You gave me a non�integer. Try again. "' ERR 2 typeset �i number # Assignment to number must be integer 3 while true do 4 print �n "Enter an integer. " 5 read �r number 2> /dev/null 6 if (( $? == 0 )) # Was an integer read in? then # Was the exit status zero?9 if grep ZOMBIE /etc/passwd > /dev/null 2>&1 then : else 10 print "$n is $n. So long" fi (The Command Line and Output) $ trap.err 4 Enter an integer. hello 1 You gave me a non�integer. Try again. 4 Enter an integer. good�bye 1 You gave me a non�integer. Try again. 4 Enter an integer. \ 1 You gave me a non�integer. Try again. 4 Enter an integer. 5 10 $n is 5. So long. $ trap.err 4 Enter an integer. 4.5 10 $n is 4. So long.
Example 15.21.
(The Script) #!/bin/bash 1 # Scriptname: wholenum # Purpose:The expr command tests that the user enters an integer -- Bash shell echo "Enter an integer." read number 2 if expr "$number" + 0 >& /dev/null then 3 : else 4 echo "You did not enter an integer value." exit 1 5 fi
There are a few errors in this script. They all relate to command-line syntax, most for bash
, but in one case for the separate expr
utility. In summary:
- The original problem related to an unmatched
`
in a backquote expression (and more generally, how to close a backquote expression and how newlines inside backquote expressions are handled by the shell). - Other syntax errors preventing your script from working properly relate to argument parsing in the
[
construct and theexpr
command.
See below for details.
The Original EOF in backquote substitution
Error
As Florian Diesch says (and in Helio’s answer also), the original problem was a missing `
at the end of the first backquoted expr ...
command. However, the more interesting aspect of this question is why do you get that error message? This is not merely a matter of idle curiosity—understanding that helps you comprehend this and other error messages in the future.
EOF stands for end-of-file and it means there are no more data available to read—in this case, text for the bash
interpreter to read. EOF is not inherently an error condition, but when an EOF is an error it usually means the interpreter thinks your program has ended prematurely—it was anticipating something, which never occurred in your program.
If the error message had said the error was an end of line in the backquote substitution, you would probably have immediately recognized the problem (provided you know that `
is called a backquote and and command substitution using a backquoted construct is also called backquote substitution).
Why does bash
think the file ends too soon, rather than the line? This is because you can actually have newlines (i.e., line breaks) inside a backquote expression:
ek@Io:~$ file `which vim
> `
/usr/bin/vim: symbolic link to `/etc/alternatives/vim'
So what’s happening is that bash reads the first backquote expression as
`expr $f* $i
i=`
which is definitely not what you intended!
Then what you intended as the contents of the second backquote expression it sees outside of backquotes, and sees the following as a second backquote expression:
`
done
echo "The factorial of $num is $f"
else
echo "Enter positive number"
fi
This is also not at all what you intended, and furthermore there is no closing backquote, which causes bash to report reaching end-of-file while still inside a backquote expression (EOF in backquote substitution
).
The solution is not to put a backquote at the very end of the script, of course! Instead, as others have said, simply add the missing backquote where it was supposed to be.
Note, however, that this must be `
, same as the opening backquote. Although the strange formatting displayed in the output of some command-line utilities might convey the impression that what begins with `
ends with '
, that is not the case. (I noticed that had at one point written a '
rather than `
for the fix.)
Closing a [
Command: The [: missing ]
Error
After fixing the first problem, you got a prog4: 5: [: missing ]
error.
In bash, [
is a command (and in fact there is even a separate [
executable, as unlike bash some shells don’t provide a [
builtin). Blank space must appear between it and its first argument.
Similarly, it is required to pass the closing ]
of a [
command as a separate command-line argument. That is, you must have blank space before the trailing ]
as well as after the leading [
.
The line
if [ "$num" -ge 0]; then
should thus be rewritten to say:
if [ "$num" -ge 0 ]; then
For more details on [
syntax, see the output of help [
and help test
.
1+1
vs. 1 + 1
After fixing that problem, you’ll get another error, which will look something like this (depending, perhaps, on what version of bash you are running):
bash: [: 1+1: integer expression expected
The problem is that expr
does not understand 1+1
is intended to mean «the sum of 1 and 1.» It does not simplify it to 2
, so the [
command that subsequently examines it doesn’t have an integer to evaluate.
Why doesn’t the expr
utility know 1+1
is supposed to be interpreted as an integer, the sum of 1 and 1? This is because each number and arithmetic operator must be passed as a separate command-line argument to expr
:
ek@Io:~$ expr 1+1
1+1
ek@Io:~$ expr 1 + 1
2
To fix this problem, rewrite the line
i=`expr $i+1`
to instead say:
i=`expr $i + 1`
Здравствуйте!
Есть скрипт:
#!/bin/bash
echo "Введите своё имя:"
read user_name
let count = `grep $user_name /etc/passwd | wc -l`
if [ $count -gt 0 ];
then
echo "В файле /etc/passwd найдено $count совпадений!"
else
echo "Нет совпадений!"
fi
Ругается:
./scrypt.sh: line 7: let: =: syntax error: operand expected (error token is «=»)
./scrypt.sh: line 9: [: -gt: unary operator expected
В чем проблема?
-
Вопрос заданболее трёх лет назад
-
3849 просмотров
У вас пробел между count между = и между собственно присваиваемым значением, в результате count пустой.
И в операторе тест у вас [ $count -gt 0] при пустой переменной $count расшифровывается как [ -gt 0 ], о чем и сообщает ошибка синтаксиса.
При использовании оператора test, всегда берите переменные в кавычки, то есть
[ «$count» -gt 0 ] или используйте продвинутый test — [[ $count -gt 0 ]], что еще лучше.
Внимательнее с пробелами — где они нужны и где не нужны.
Пригласить эксперта
-
Показать ещё
Загружается…
09 февр. 2023, в 10:11
1500 руб./в час
09 февр. 2023, в 09:53
10 руб./за проект
09 февр. 2023, в 09:28
5000 руб./за проект