在意外令牌“完成”附近出现Shell语法错误

时间:2012-04-27 03:55:23

标签: shell token

此shell脚本应该将用户添加到系统中。新用户详细信息位于文件中。 shell使用以下消息拒绝此脚本:

syntax error near unexpected token 'done'.

怎么了?

#!/bin/bash
#Purpose: Automatically add new users in a linux system based upon the data found within a text file
#         Assign encryped passwords to each user
#         Add users to groups or create new groups for these users
#         Report errors and successful operations where necessary in log files
#         post help options (echo)

#Root validation
if [[ $(id -u) -eq 0 ]]; then
  #Argument validation
  if [[ -z "$1" ]]; then
    echo "No arguments found!"
    echo "Please include a user detail text file as first argument"
    echo "Please include a report text file as second argument"
    echo "Please include an error report text file as the third argument"
    echo "Use the -h argument (i.e. ./script -h) for help"
  exit 1
fi

#Help validation and Help file
if [[ "$1" = "-h" ]]; then
  echo "This is the help information file"
  echo "This script is designed to add users to a linux system by reading information from a user detail file (such as userlist.txt)"
  echo "The format of this user detail text file is "username password groupname fullname" seperated using TAB spacing"
  echo "This script will read the first argument as the user detail file, the second and third arguments will be read as a success report file and error report file respectively"
  exit
fi

#Reads first argument as user detail file for data
cat userlist.txt | while read uname password gname fullname
#Reads /etc/passwd for Username
egrep -w "^$uname" /etc/passwd
#If Username is found then error reports
if [ $? == 0 ]; then
  echo "User Already Exists : Error adding user with username $uname;$gname;$fullname" >> Successes1.log
  exit 1
else
  #Reads /etc/group for Groupname
  egrep -w "^$gname" /etc/group
  #If Groupname is found then nothing
  if [ $? == 0 ]; then
    echo ""
  else
    #If Groupname not found then creates new group and reports
    groupadd "$gname"
    echo "Group Not Found: New Group $gname was created" >> Successes1.log
  fi
  #Retrieves Date
  createddate=$(date)
  #Perl password script takes input from Userlist
  pass=$(perl -e 'print crypt($ARGV[0], "Password")' "$password")
  #Adds Users with variables from userlist
  useradd "$uname" -g "$gname"  -c "$fullname" -p "$pass"
  #Reports information to successlist and errorlist report files
  if [ $? == 0 ]; then
    groupid=$(id -g $uname)
    userid=$(id -u $uname)
    echo "User Successfully Added: $uname;$userid;$gname;$groupid;$createddate;$fullname" >> Successes1.log
  else
    groupid=$(id -g $uname)
    userid=$(id -u $uname)
    echo "Useradd Error Occurred: $uname;$userid;$gname;$groupid;$createddate;$fullname" >> Errors1.log
    echo "Error: Must be root user to execute script"
    exit
  fi
done

第二次尝试

使用答案中的一些想法,我想出了第二次尝试:

#!/bin/bash
#Purpose: Automatically add new users in a linux system based upon the data found within a text file
#         Assign encryped passwords to each user
#         Add users to groups or create new groups for these users
#         Report errors and successful operations where necessary in log files
#         post help options (echo)

#Root validation
if [[ $(id -u) -eq 0 ]]; then
  #Argument validation
  if [[ -z "$1" ]]; then
    echo "Usage: $0 usernames report errors" 1>&2
    echo "Please include a user detail text file as first argument"
    echo "Please include a report text file as second argument"
    echo "Please include an error report text file as the third argument"
    echo "Use the -h argument (i.e. ./script -h) for help"
    exit 1
  fi
fi

#Help validation and Help file
if [[ "$1" = "-h" ]]; then
  echo "This is the help information file"
  echo "This script is designed to add users to a linux system by reading information from a user detail file (such as userlist.txt)"
  echo "The format of this user detail text file is "username password groupname fullname" seperated using TAB spacing"
  echo "This script will read the first argument as the user detail file, the second and third arguments will be read as a success report file and error report file respectively"
  exit
fi

#Reads first argument as user detail file for data
cat jan.txt | while read uname password gname fullname; do
#Reads /etc/passwd for Username
 egrep -w "^$uname:" /etc/passwd >/dev/null 2>&1
#If Username is found then error reports
if [ $? == 0 ] 
then
  echo "User Already Exists : Error adding user with username $uname;$gname;$fullname" >> Errors1.log

else
  #Reads /etc/group for Groupname
  egrep -w "^$gname" /etc/group
  #If Groupname is found then nothing
if [ $? == 0 ]; then
    echo ""
else
  #If Groupname not found then creates new group and reports
  groupadd "$gname"
    echo "Group Not Found: New Group $gname was created" >> Successes1.log
done < $1
#Retrieves Date
createddate=$(date)
#Perl password script takes input from Userlist
pass=$(perl -e 'print crypt($ARGV[0], "Password")' "$password")
#Adds Users with variables from userlist
useradd "$uname" -g "$gname"  -c "$fullname" -p "$pass"
#Reports information to successlist and errorlist report files
if [ $? == 0 ]
then
  groupid=$(id -g $uname)
  userid=$(id -u $uname)
  echo "User Successfully Added: $uname;$userid;$gname;$groupid;$createddate;$fullname" >> Successes1.log
else
  groupid=$(id -g $uname)
  userid=$(id -u $uname)
  echo "Useradd Error Occurred: $uname;$userid;$gname;$groupid;$createddate;$fullname" >> Errors1.log
  echo "Error: Must be root user to execute script"
  exit 1
fi
fi
done

这似乎也不正常。现在怎么了? 似乎显示参数和运行但是没有添加用户或组,因此没有创建日志

3 个答案:

答案 0 :(得分:5)

if从:

开始
if [ $? == 0 ]; then
  echo "User Already Exists : Error adding user with username ...
  exit 1
else

done而不是所需的fi结束。

while循环早先开始几行:

cat userlist.txt | while read uname password gname fullname

缺少do(另一个错误);如果存在,那么最后还需要done。有人忘记了缩进。 (每个级别使用2个字符优于0或1,但如果每个级别使用4个空格,则更容易跟踪级别。)请注意,shell没有抱怨缺少do,因为while循环的语法是:

while cmd1
      cmd2
      cmd3 ...
do

就shell而言,它仍在处理列表cmd1, cmd2, cmd3, ...中的命令。


这是脚本的半体面缩进版本。脚本顶部也缺少fi

#!/bin/bash
#Purpose: Automatically add new users in a linux system based upon the data found within a text file
#         Assign encryped passwords to each user
#         Add users to groups or create new groups for these users
#         Report errors and successful operations where necessary in log files
#         post help options (echo)

#Root validation
if [[ $(id -u) -eq 0 ]]
then
    #Argument validation
    if [[ -z "$1" ]]
    then
        echo "No arguments found!"
        echo "Please include a user detail text file as first argument"
        echo "Please include a report text file as second argument"
        echo "Please include an error report text file as the third argument"
        echo "Use the -h argument (i.e. ./script -h) for help"
        exit 1
    fi
fi

#Help validation and Help file
if [[ "$1" = "-h" ]]
then
    echo "This is the help information file"
    echo "This script is designed to add users to a linux system by reading information from a user detail file (such as userlist.txt)"
    echo "The format of this user detail text file is "username password groupname fullname" seperated using TAB spacing"
    echo "This script will read the first argument as the user detail file, the second and third arguments will be read as a success report file and error report file respectively"
    exit
fi

#Reads first argument as user detail file for data
cat userlist.txt | while read uname password gname fullname
do
    #Reads /etc/passwd for Username
    egrep -w "^$uname" /etc/passwd
    #If Username is found then error reports
    if [ $? == 0 ]
    then
        echo "User Already Exists : Error adding user with username $uname;$gname;$fullname" >> Successes1.log
        exit 1
    else
        #Reads /etc/group for Groupname
        egrep -w "^$gname" /etc/group
        #If Groupname is found then nothing
        if [ $? == 0 ]
        then
            echo ""
        else
            #If Groupname not found then creates new group and reports
            groupadd "$gname"
            echo "Group Not Found: New Group $gname was created" >> Successes1.log
        fi
        #Retrieves Date
        createddate=$(date)
        #Perl password script takes input from Userlist
        pass=$(perl -e 'print crypt($ARGV[0], "Password")' $pass)
        #Adds Users with variables from userlist
        useradd "$uname" -g "$gname"  -c "$fullname" -p "$pass"
        #Reports information to successlist and errorlist report files
        if [ $? == 0 ]
        then
            groupid=$(id -g $uname)
            userid=$(id -u $uname)
            echo "User Successfully Added: $uname;$userid;$gname;$groupid;$createddate;$fullname" >> Successes1.log
        else
            groupid=$(id -g $uname)
            userid=$(id -u $uname)
            echo "Useradd Error Occurred: $uname;$userid;$gname;$groupid;$createddate;$fullname" >> Errors1.log
            echo "Error: Must be root user to execute script"
            exit
        fi
    fi
done

仍有很大的改进空间。如果用户不是root用户,则应退出根验证块;相反,它发生在循环内的一英里处。您可以更好地检查参数的数量:$#为您提供参数的数量。如果我尝试yourscript.sh '' arg2 arg3,你会声称没有参数,实际上问题是$1存在但是是一个空字符串。报告如何使用命令的标准约定如下:

echo "Usage: $0 usernames report errors" 1>&2

报告命令的名称和预期的参数。 1>&2将消息发送到标准错误而不是标准输出。这里的逻辑有点奇怪,即便如此。您检查用户是否为root,然后检查是否存在参数。如果用户不是root用户,则不检查参数。我提交并不完全合理。

我们可以辩论UUOC(无用的猫)。实际上有一个奖项;我不认为这符合条件。但是,可以写:

while read uname password gname fullname
do
    ...
done < $1

嗯......脚本应该采用指定用户的文件名参数,但cat采用固定文件名,而不是文件名参数!

同样,论点2和3被刻意忽略;日志文件是硬编码的。

egrep -w "^$uname" /etc/passwd
#If Username is found then error reports
if [ $? == 0 ]

这个片段可以通过以下几种方式进行改进:

if egrep -w "^$uname:" /etc/passwd >/dev/null 2>&1
then
    #If Username is found then error report

直接测试egrep命令的退出状态;它还会阻止新用户roo因用户root而被视为预先存在。它将输出和错误输出发送到/dev/null,这样当用户存在时您将看不到任何内容。

最好不要在找到用户名时退出;你至少可以尝试处理下一个条目。用户存在的报告(终止处理)也记录在Successes1.log而不是Errors1.log中,这也很奇怪;它被视为错误。

组检查结构类似,应该进行类似的升级。

您使用$password行将密码读入read;但是,在创建密码方面,你有:

pass=$(perl -e 'print crypt($ARGV[0], "Password")' $pass)

在第一个周期,$pass为空(最有可能);你最后应该在双引号中使用$password

pass=$(perl -e 'print crypt($ARGV[0], "Password")' "$password")

egrep命令一样,您也可以直接检查useradd命令的状态。说if [ $? == 0 ]是一个tyro的标志有点彻底,但事实并非如此。

脚本中的最终exit应为exit 1,表示错误退出。如前所述,这之前是关于“你必须是root”的评论,即使在顶部检查了root权限。

警告:我没有尝试过运行脚本;我很容易错过一些问题。但是,它确实通过了sh -v -n,因此没有遗漏任何严重的语法错误。

一旦shell脚本在语法上正确,那么你通常使用sh -x script调试它(或者,如果它需要参数,那么sh -x script arg1 arg2 arg3 ...)。这是执行跟踪模式。 shell或多或少地告诉你,它正在做什么。信息写入标准错误。如果您愿意,您甚至可以将输出捕获以供日后审查:

sh -x script arg1 arg2 arg3 2>script-x.log

2>script-x.log表示法将标准错误发送到文件script-x.log(选择您自己有意义的名称;我经常使用xxxx来查找我不想要的文件保持,但我也删除这些文件,甚至没有看到它们,因为我知道它们是一次性文件。)

答案 1 :(得分:0)

“完成”应该与之前的“做”配对 它不是你脚本的结尾。

答案 2 :(得分:0)

您的while缺少do

cat userlist.txt | while read uname password gname fullname
do 

cat userlist.txt | while read uname password gname fullname; do