Keywords: Bash syntax error | if statement repair | shell script debugging
Abstract: This article provides an in-depth analysis of the common 'syntax error near unexpected token 'fi'' error in Bash scripts. Through detailed code examples, it explains the root causes and provides comprehensive solutions. Starting from Bash syntax rules, the article covers proper if statement formatting, the importance of spaces in conditional tests, variable handling techniques, and complete repair strategies. Additionally, it extends the discussion to Bash conditional statement parsing mechanisms and best practices based on reference materials, helping readers fundamentally avoid similar syntax errors.
Error Phenomenon and Code Analysis
In Bash script development, syntax errors are common issues. A user reported encountering a "syntax error near unexpected token 'fi'" error while executing a script to remove .jpg files ending with odd numbers. Let's first analyze the original code:
#!/bin/bash
echo "start\n"
for f in *.jpg
do
fname=$(basename "$f")
echo "fname is $fname\n"
fname="${filename%.*}"
echo "fname is $fname\n"
if[$((fname % 2)) -eq 1 ] then
echo "removing $fname\n"
rm $f
fi
done
Deep Analysis of Error Causes
After careful analysis, the script contains multiple syntax issues:
First, the if statement format is incorrect. In Bash, if statements require specific syntax structures. When the then keyword is on the same line as the conditional test, a semicolon must be used as a separator; alternatively, then can be placed on a new line. The original code if[$((fname % 2)) -eq 1 ] then lacks the necessary separator.
Second, space handling in conditional tests is improper. In Bash, [ is actually a command (usually an alias for the test command), so it requires spaces before and after the command name, just like other commands. The original code if[$((fname % 2)) -eq 1 ] lacks spaces around [.
Additionally, there is variable name inconsistency: fname="${filename%.*}" should use fname instead of filename.
Repair Solution and Complete Code
Based on the above analysis, we provide a complete repair solution:
#!/bin/bash
echo "start\n"
for f in *.jpg
do
fname=$(basename "$f")
echo "fname is $fname\n"
fname="${fname%.*}"
echo "fname is $fname\n"
if [ $((fname % 2)) -eq 1 ]
then
echo "removing $fname\n"
rm "$f"
fi
done
Key modifications include:
- Moving the
thenkeyword to a new line in theifstatement - Adding necessary spaces before and after
[ - Correcting the variable name from
filenametofname - Adding quotes around the filename variable in the
rmcommand to prevent issues with filenames containing spaces
Bash Conditional Statement Parsing Mechanism
According to the in-depth analysis from reference materials, keywords like if, then, else, fi in Bash need to appear in positions where the shell expects command names; otherwise, they are treated as ordinary words.
In conditional statements like if [ condition ] then, if proper separators are missing, then will be parsed as an argument to the [ command rather than as a keyword of the conditional statement. The shell continues to look for the then keyword, and when it encounters fi, since there's still an unfinished if statement waiting for then, the appearance of fi is "unexpected," resulting in a syntax error.
Best Practice Recommendations
To avoid similar syntax errors, it is recommended to:
- Always maintain spaces before and after
[and] - Use consistent
ifstatement formatting: either use semicolon separation on the same line or placethenon a new line - For complex conditional tests, consider using the
[[ ... ]]syntax, which provides better operator support and variable handling - Always quote variables in filename operations to prevent issues with spaces and special characters
By understanding Bash's parsing mechanisms and following correct syntax rules, you can effectively avoid "syntax error near unexpected token" type errors and write more robust shell scripts.