LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 01-05-2012, 09:24 AM   #1
Fraeco
LQ Newbie
 
Registered: Mar 2009
Posts: 5

Rep: Reputation: 0
Bash scripting error (unexpected end of line)


I've been writing a script to maintain users on our new ftp server.

When I try to run it I'm getting a rather annoying "/addftp: line 65: syntax error: unexpected end of file" error.

I've been looking arround a bit and found some reference to not closing quotes etc, but I think I've been over the script a dozen times now, and haven't found any open quotes or anything else out of the ordinary.

Can you guys take a look at the script and see what I am missing?

Code:
#!/bin/bash

USERFILE="/etc/vsftpd/virtual-users.txt"
DBFILE="/etc/vsftpd/virtual-users.db"

function userdata {
        echo $username > $USERFILE
        echo $password >> $USERFILE
        db4.8_load -T -t hash -f $USERFILE $DBFILE
        rm $USERFILE
}

choice=4
echo "1. Create a new user"
echo "2. Change the password of an existing user"
echo "3. Disable an existing user"
echo -n "Choose wisely"
while [ $choice -eq 4 ] ; do
read choice

if [ $choice -eq 1 ] ; then
        echo "Starting FTP virtual user creation."
        echo "Please enter the new username"
        read username
        echo "Please choose a password for the new user"
        read -s password
        userdata
        echo "Creating user homefolder"
        mkdir /home/ftp/$username
        chown ftp:ftp /home/ftp/$username
        echo "User $username with homedirectory /home/ftp/$username created."

else

        if [ $choice -eq 2 ] ; then
        echo "Changing user password"
        echo "Please enter the username"
        read username
        echo "Please enter the new password"
        read -s password
        userdata
        echo "Password of $username changed"

        else
                if [ $choice -eq 3 ] ; then
                echo "Disabling FTP user"
                echo "Please enter the username"
                read username
#               echo "Delete existing user folder and contents? y/n"
#               read delete
#                       if [ $delete -eq y ] ; then
#                       echo "Removing /home/ftp/$USERNAME"
#                       rm -R /home/ftp/$USERNAME
#                       else
                password=accessnomoreyoucanhaz
                userdata
                else
                echo "Please choose a valid option"
                choice=4
                fi
        fi
fi
The commented part is still a work in progress, so don't really need to bother much with that
 
Old 01-05-2012, 09:36 AM   #2
thesnow
Member
 
Registered: Nov 2010
Location: Minneapolis, MN
Distribution: Ubuntu, Red Hat, Mint
Posts: 172

Rep: Reputation: 56
You're missing the "done" after the "do" to end the while loop.

However, do you really need the while loop? The way it's constructed it's only going to run through once, then quit, because choice is only 4 initially, not selected as an option by the user. You could just take the whole "while" line out, read "choice" and the rest of the script should run based on the selection.

Last edited by thesnow; 01-05-2012 at 09:42 AM. Reason: Additional thoughts
 
Old 01-05-2012, 09:52 AM   #3
soppy
Member
 
Registered: Mar 2008
Location: In your head!
Distribution: Arch Linux
Posts: 165
Blog Entries: 1

Rep: Reputation: 28
Here is the fixed code....There were some errors that I'd like to point out. This runs flawlessly now.

Code:
#!/bin/bash

USERFILE="/etc/vsftpd/virtual-users.txt"
DBFILE="/etc/vsftpd/virtual-users.db"

function userdata {
        echo $username > $USERFILE
        echo $password >> $USERFILE
        db4.8_load -T -t hash -f $USERFILE $DBFILE
        rm $USERFILE
}

choice=4
echo "1. Create a new user"
echo "2. Change the password of an existing user"
echo "3. Disable an existing user"
echo -n "Choose wisely: "

read choice

if [ $choice -eq 1 ] ; then
        echo "Starting FTP virtual user creation."
        echo "Please enter the new username"
        read username
        echo "Please choose a password for the new user"
        read -s password
        userdata
        echo "Creating user homefolder"
        mkdir /home/ftp/$username
        chown ftp:ftp /home/ftp/$username
        echo "User $username with homedirectory /home/ftp/$username created."

	elif [ $choice -eq 2 ] ; then
		echo "Changing user password"
		echo "Please enter the username"
		read username
		echo "Please enter the new password"
		read -s password
		userdata
		echo "Password of $username changed"

        elif [ $choice -eq 3 ] ; then
               echo "Disabling FTP user"
               echo "Please enter the username"
               read username
#           echo "Delete existing user folder and contents? y/n"
#               read delete
#                       if [ $delete -eq y ] ; then
#                       echo "Removing /home/ftp/$USERNAME"
#                       rm -R /home/ftp/$USERNAME
#                       else
            password=accessnomoreyoucanhaz
            userdata
         
         else
                echo "Please choose a valid option"
                choice=4
fi
Now for an explanation...
Code:
while [ $choice -eq 4 ] ; do
I take it you're a compiled language programmer (C/C++)? This is a common mistake. Read will already pause for input, we don't need to create this loop here. And if we did, we'd have to close it off with a "done".

Code:
if [ $choice -eq 1 ] ; then
        echo "Starting FTP virtual user creation."
        echo "Please enter the new username"
        read username
        echo "Please choose a password for the new user"
        read -s password
        userdata
        echo "Creating user homefolder"
        mkdir /home/ftp/$username
        chown ftp:ftp /home/ftp/$username
        echo "User $username with homedirectory /home/ftp/$username created."

else

        if [ $choice -eq 2 ] ; then
        echo "Changing user password"
        echo "Please enter the username"
        read username
        echo "Please enter the new password"
        read -s password
        userdata
        echo "Password of $username changed"

        else
                if [ $choice -eq 3 ] ; then
                echo "Disabling FTP user"
                echo "Please enter the username"
                read username
#               echo "Delete existing user folder and contents? y/n"
#               read delete
#                       if [ $delete -eq y ] ; then
#                       echo "Removing /home/ftp/$USERNAME"
#                       rm -R /home/ftp/$USERNAME
#                       else
                password=accessnomoreyoucanhaz
                userdata
                else
                echo "Please choose a valid option"
                choice=4
                fi
        fi
fi
You have NO IDEA how close you were here...except these else and if statements won't work in eachother. Instead, you need to use the "elif" command (else if) to test the number. So if it's 1, do this. Else if it's 2, do this. Else if it's 3...etc etc. Bash simply doesn't like the way you did it and it got lost. It's very picky like that...

To be honest, I wouldn't even use all those else if statements, I would've used a switch case. It's a lot cleaner and less code.

Hope I helped out!!!
 
Old 01-05-2012, 05:22 PM   #4
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
I second that recommendation. Use a case statement instead (shells don't use the word "switch"). It's almost always better for evaluating the contents of a single variable for a set list of values. Use if/elif/else when the tests you need are more complex and varied (i.e. if $a = foo, elif $b != bar, elif $c = baz && $d != bum...).


Two more general points about scripting in bash:

1) It's recommended to use ((..)) for numerical tests, and [[..]] for string tests and other complex expressions. Don't use the old [..] test unless you specifically need POSIX-style portability.

http://mywiki.wooledge.org/BashFAQ/031
http://mywiki.wooledge.org/ArithmeticExpression

2) QUOTE ALL OF YOUR VARIABLE SUBSTITUTIONS. You should never leave the quotes off a variable expansion unless you explicitly want the resulting string to be word-broken by the shell. This is a vitally important concept in scripting, so train yourself to do it correctly now. You can learn about the exceptions later.

http://mywiki.wooledge.org/Arguments
http://mywiki.wooledge.org/WordSplitting
http://mywiki.wooledge.org/Quotes

Last edited by David the H.; 01-05-2012 at 05:24 PM. Reason: small update
 
1 members found this post helpful.
Old 01-06-2012, 04:29 AM   #5
Fraeco
LQ Newbie
 
Registered: Mar 2009
Posts: 5

Original Poster
Rep: Reputation: 0
The entire "case" idea is great!

I've rewritten to this
Code:
#!/bin/bash
USERFILE="/etc/vsftpd/virtual-users.txt"
DBFILE="/etc/vsftpd/virtual-users.db"

function userdata {
        echo "$username" > "$USERFILE"
        echo "$password" >> "$USERFILE"
        db4.8_load -T -t hash -f "$USERFILE" "$DBFILE"
        rm "$USERFILE"
}

echo "1. Create a new user"
echo "2. Change the password of an existing user"
echo "3. Disable an existing user"
echo -n "Choose wisely: "
read choice

case "$choice" in
1)
        echo "Starting FTP virtual user creation."
        echo "Please enter the new username"
        read username
        echo "Please choose a password for the new user"
        read -s password
        userdata
        echo "Creating user homefolder"
        mkdir /home/ftp/$username
        chown ftp:ftp /home/ftp/$username
        echo "User $username with homedirectory /home/ftp/$username created."
        ;;
2)
        echo "Changing user password"
        echo "Please enter the username"
        read username
        echo "Please enter the new password"
        read -s password
        userdata
        echo "Password of $username changed"
        ;;

3)
        echo "Disabling FTP user"
        echo "Please enter the username"
        read username
                echo -n "Delete existing user folder and contents? y/n"
                read delete
                case "$delete" in
                [yY] | [yY][Ee][Ss] )
                        echo "Removing /home/ftp/$username"
                        rm -R /home/ftp/$username
                        ;;
                [nN] | [n|N][O|o] )
                        echo "Not removing /home/ftp/$username"
                        ;;
                *)
                        echo "You failed! Not removing anything now. Take the next few seconds to think about yourself"
                        sleep 10
                        ;;
                esac
        password=accessnomoreyoucanhaz
        userdata

        ;;
*)
        echo "Please choose a valid option. 1, 2 or 3"
esac
Alltough, there's one minor problem. Is there a possibility to let the script go back to top if the case is "*"?

Last edited by Fraeco; 01-06-2012 at 04:50 AM.
 
Old 01-06-2012, 07:52 PM   #6
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
Sure! Just embed it inside a while true loop!

Then use a break command to exit the loop when you want it to. Make sure the read is part of the loop, of course, so you have new input to test each time.

It's the traditional way to create a repeating menu in scripting.

You can also choose to use a select loop instead, which is a built-in that provides a pre-configured looping menu. It pretty much just does the same thing in the end though.

http://wiki.bash-hackers.org/syntax/ccmd/user_select
http://www.tldp.org/LDP/abs/html/testbranch.html
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
line 23 :syntax error unexpected end of file detected nipuniitg Linux - Software 8 11-13-2011 02:12 PM
Error in Bash: line 77: syntax error: unexpected end of file bribon Programming 8 07-13-2011 12:43 PM
-bash: *.sh: line 25: syntax error: unexpected end of file prashanth212 Linux - General 8 04-05-2010 11:52 PM
bash line 74: syntax error: unexpected end of file help? andycol Linux - General 5 09-14-2009 08:12 AM
Simple bash script "unexpected end of line error" snowman81 Programming 11 11-11-2007 09:31 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 07:28 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration