Shell脚本语法错误:意外的文件结尾

84
在下面的脚本中,我遇到了一个错误:

语法错误:意外的文件结尾

这是什么错误?我该如何解决它?它指向调用函数的那一行。
#!/bin/sh

expected_diskusage="264"
expected_dbconn="25"
expected_httpdconn="20"
expected_cpuusage="95"
#expected_fd="100"

httpdconn=`ps -ef|grep -i httpd|grep -v grep|wc -l` #httpd connections
cpu_usage=`ps aux|awk 'NR > 0 { s +=$3 }; END {print s}'`
disk_usage=`df -h|awk {'print $2'}|head -n3|awk 'NF{s=$0}END{print s}'`
#db_connections=`mysql -uroot -pexxxxxx -s -N -e "show processlist"|wc -l`

db_connections=6
cld_alert()
{
    nwconn=$1
    cpu_usage=$2
    disk_usage=$3
    db_connections=$4
    message=$5
    `touch /tmp/alert.txt && > /tmp/alert.txt`
    date=`date`
    echo -e "$date\n" > /tmp/alert.txt
    echo -e "$message" >> /tmp/alert.txt
    path="/proc/$httpd/fd/";
    cd $path
    tfd=`ls -l|wc -l`;
    sfd=`ls -ltr|grep sock|wc -l`;
    echo "Total fds: $tfd" >> /tmp/alert.txt
    echo "Socket fds: $sfd" >> /tmp/alert.txt
    echo "Other fds: $[$tfd - $sfd]" >> /tmp/alert.txt


    freememory=`vmstat | awk '{if (NR == 3) print "Free Memory:"\$4}'`;
    echo "Free memory :$freememory" >> /tmp/alert.txt
    Bufferedmemory=`vmstat | awk '{if (NR == 3) print "Buffered Memory:"\$5}'`;
    echo "Buffered memory $Bufferedmemory" >> /tmp/alert.txt
    CacheMemory=`vmstat | awk '{if (NR == 3) print "Cache Memory:"\$6}'`;
    echo "Cache memory : $CacheMemory" >> /tmp/alert.txt
    sshconn=`netstat -an|grep 22|wc -l`  #ssh connections
    httpsconn=`netstat -an|grep 443|wc -l`  #https connections
    wwwconn=`netstat -an|grep 80|wc -l`  #www connections
    echo "Disk usage is $disk_usage" >> /tmp/alert.txt
    echo "DB connections $db_connections" >> /tmp/alert.txt
    echo "Network connections $nwconn" >> /tmp/alert.txt
    echo "CPU Usage: $cpu_usage" >> /tmp/alert.txt
    topsnapshot=`top -n 1 -b`
    echo "===========================TOP COMMAND    SNAPSHOT====================================================";
    echo "$topsnapshot" >> /tmp/alert.txt
    echo"==================PS COMMAND SNAPSHOT=============================================================="
    entireprocesslist=`ps -ef`
    echo "$entireprocesslist" >> /tmp/alert.txt


    echo Hello hi"";

}



message=""
if [ ${disk_usage%?} -le $expected_diskusage ]    ##{x%?} Removes last character
then
    echo "disk usage exceeded";
    message="Disk usage limit exceeded \nCurrent disk usage is $disk_usage\nConfigured disk usage is    $expected_diskusage\n\n\n\n\n";
    #Checking for CPU usage
    if [ $cpu_usage -ge $expected_cpuusage]    ##{x%?}
    then
        echo "CPU usage exceeded";
        if [ $message -ne "" ]
        then
            message="$message\n\nCPU usage exceeded configured usage limit \nCurrent CPU usage is $cpu_usage\nConfigured CPU usage is $expected_cpuusage\n\n\n\n\n";
        else
            message="CPU usage exceeded configured usage limit \nCurrent CPU usage is   $cpu_usage\nConfigured CPU usage is $expected_cpuusage\n\n\n\n\n";
        fi ;
    fi
    #Checking for httpd connections
    if [ $httpdconn -ge $expected_httpdconn]    ##{x%?}
    then
        echo "HTTPD connections exceeded";
        if [ $message -ne "" ]
        then
            message="$message\n\nHTTPD connections exceeded configured usage limit \nCurrent HTTPD connections is $httpdconn\nConfigured HTTPD connection is $expected_httpdconn";
        else
            message="HTTPD connections exceeded configured usage limit \nCurrent HTTPD connections is $httpdconn\nConfigured HTTPD connection is $expected_httpdconn";
        fi ;
    fi ;
    message="$message\n\n\n\n\n";
    value=$(cld_alert $message $httpdconn $cpu_usage $disk_usage $db_connections)

1
请只返回翻译后的文本:请复制整个脚本(好吧,我们希望能看到能够重现问题的最小化代码,但您已经没有发布那个...) - Karoly Horvath
错误很可能出现在此之前。 - Mat
3
按嵌套级别对代码进行缩进。每个缩进级别至少4个空格,这样你就可以真正地看到结构。很可能某个地方缺少了fi},但如果没有缩进,你永远不会知道缺少在哪里。 - Jan Hudec
在最后一行赋值中,赋的值有什么作用呢 - 这个值从未被使用过。 - user unknown
尝试使用 https://www.shellcheck.net/ 进行Shell检查。 - user26742873
显示剩余2条评论
12个回答

150

编辑:请注意,自回答撰写以来,原帖已被编辑并重新格式化。您应查看历史记录以查看原始格式,以了解此答案的上下文。

当您的结构不匹配时,就会经常出现此错误——也就是说,您没有匹配的双引号,匹配的单引号,未关闭控制结构(例如缺少 iffi 或缺少 fordone)等。

发现这些问题的最佳方法是使用正确的缩进,这将向您显示破损的控制结构的位置,以及语法高亮,这将向您显示引号不匹配的位置。

在这种特定情况下,我可以看到您缺少一个 fi。在代码的后半部分中,您有 5 个 if 和 4 个 fi。但是,您还有许多其他问题——您的反引号 touch /tmp/alert.txt... 命令在语法上无效,并且在 if 测试的关闭括号之前需要一个空格。

整理您的代码,错误就会显现出来。


1
太棒了!这真的很有帮助。这些都是常见的小细节,容易被忽略。请继续添加 :) - Shobhit Puri
非常感谢 :-) - Sudarshana Dayananda
2
ShellCheck非常适合查找确切的错误位置,甚至可能会发现更多的错误或警告。 - SimonH
shfmt是另一个工具,自从我回答这个问题以来已经发布了,它可以帮助您清理代码。shellcheck和shfmt是编写shell脚本的必备工具。 - camh

58

在我的情况下,问题出现在EOL转换(行尾符)上。

我是在Windows上创建了该文件,只有在将EOL从Windows(CR LF)转换为Unix(LF)后,一切才顺利进行。

我使用Notepad++很容易地进行了转换: 编辑-> EOL转换-> Unix(LF)


12
这个答案对我很有帮助。在使用 vscode 编辑器时,需要将编辑器右下角的CRLF更改为LF - cjmling
2
这对我很有帮助。我在WSL中运行我的文件,但文件是在Windows记事本++中创建的。 - Tushar Gautam
2
这个有帮助,和 @cjmling说的完全一样的方法。 - Minh Kha

17

与 OP 的问题无关,但我的问题是我只是一个新手 Shell 脚本编写者。我使用过的所有其他语言都需要使用括号来调用方法,而 Shell 看起来不喜欢这样。

function do_something() {
  # do stuff here
}

# bad
do_something()

# works
do_something

2
它已经生效了,谢谢。 - C.V
是的,忘记了。 - undefined

11
在我的情况下,我发现将here文档(如sqplus ... << EOF)放在缩进的语句中也会引发与下面显示的相同的错误:

./dbuser_case.ksh: line 25: syntax error: unexpected end of file

所以在去掉缩进后,它顺利执行了。

希望能对你有所帮助...


1
这个!我在一个if块中使用了heredoc。在块中有未缩进的代码感觉很不对,但这是绝对必要的。 - Zeal

10
使用块时缩进可能会导致此错误,并且很难找到。
if [ ! -d /var/lib/mysql/mysql ]; then
   /usr/bin/mysql --protocol=socket --user root << EOSQL
        SET @@SESSION.SQL_LOG_BIN=0;
        CREATE USER 'root'@'%';
   EOSQL
fi

=> 上面的示例会导致错误,因为EOSQL有缩进。请按照以下所示删除缩进。我发布这个内容是因为我花了一小时才找到错误。

if [ ! -d /var/lib/mysql/mysql ]; then
   /usr/bin/mysql --protocol=socket --user root << EOSQL
        SET @@SESSION.SQL_LOG_BIN=0;
        CREATE USER 'root'@'%';
EOSQL
fi

5
当你说这个错误“非常难”找到时,你并不是在开玩笑。 - Kenan
如果我能为你的回答颁发奖章就好了。谢谢。这个缩进让我浪费了半天时间!! - likeGreen

6

我发现这有时是由于运行MS Dos版本的文件导致的。如果是这种情况,应使用dos2ux修复。

dos2ux file1 > file2

4

4

这是一篇有用的文章,我发现我的错误在于使用了 else if 而不是 elif,正确写法如下:

if [ -z "$VARIABLE1" ]; then
    # do stuff
else if [ -z "$VARIABLE2" ]; then
    # do other stuff
fi

通过更改为以下内容,已解决此问题:

if [ -z "$VARIABLE1" ]; then
    # do stuff
elif [ -z "$VARIABLE2" ]; then
    # do other stuff
fi

1
来自将近9年后的感谢。 - Thomas Wood

3

您的引号、括号、大括号、if语句、循环语句等未关闭。

如果您无法通过直接查看代码找到问题(我建议使用语法高亮编辑器和规范的缩进风格),请将脚本复制一份,并删除其中一半,剪切一个应该是有效的位置。如果脚本能够运行到某个程度,那么问题就在另一半中。重复此过程,直到您缩小了问题的范围。


2
echo"==================PS COMMAND SNAPSHOT=============================================================="

需要被
echo "==================PS COMMAND SNAPSHOT=============================================================="

否则,将搜索名为echo"===...的程序或命令。

更多问题:

如果您使用grep(-A1:+ 1行上下文)

grep -A1 "if " cldtest.sh 

你发现了一些嵌套的if语句,以及4个if/then代码块。
grep "fi " cldtest.sh 

只显示了3个匹配的fi语句。所以你还忘记了一个fi。

我同意camh的观点,正确的缩进从一开始就有助于避免这种错误。在这样的"意大利面式"代码中稍后找到所需的方法意味着要做双倍的工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接