Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

SRossi

macrumors regular
Original poster
May 27, 2009
202
0
Glasgow, Scotland
Hey all,

Doing another script and wanted to test it even although I haven't finished it yet. Giving me the error:
Code:
work OS.sh: line 180: syntax error near unexpected token `;;'
work OS.sh: line 180: `;;'

Right I understand that its near the ;; at the end of '1') for the case statement, when i take away the esac from the nested case it gives the same error, all that I could think was that it didn't like the nested case. But I'm really unsure whats wrong.

Could someone have a look a a show me where my stupidness is please. :)

Code:
#!/bin/bash
# Stephen Ross' Backup Script

# Declaring the variables and the path names
BackupWp = /Users/rosstephen/Documents/wp/Archive_$(date '+%d.%m.%y:%H:%M').tgz
BackupSs = /Users/rosstephen/Documents/ss/Archive_$(date '+%d.%m.%y:%H:%M').tgz
BackupPic = /Users/rosstephen/Documents/pics/Archive_$(date '+%d.%m.%y:%H:%M').tgz

Restore = /Users/rosstephen/Documents

# Begin while statement
while true;
do

# User choice menu - Main Menu

	clear
	echo ****************************************************************
	echo 				Backup and Restore
	echo ****************************************************************
	echo Please select an option from 1-3:
	echo
	echo "1) Create a backup"
	echo
	echo "2) Restore a file from a backup"
	echo
	echo "3) Exit system"
	echo

# Read user input
read USERCHOICE

# Begin the case statement
case $USERCHOICE in


'1')	# Begin another while statement
	while true;
	do
	
	# User choice menu - Backup Menu

	clear
	echo ******************************************************************
	echo					Backup
	echo ******************************************************************
	echo Please select an option 1-4:
	echo
	echo "a) Backup text document"
	echo
	echo "b) Backup spreadsheet document"
	echo
	echo "c) Backup picture"
	echo
	echo "d) Return to Main Menu"
	echo
	
	# Read user input
	read USERCHOICE2
	
	# Begin the next case statement
	case $USERCHOICE2 in

	'a')	clear
		echo Backup of Text Document
		sleep 2
		
		# Ask user for the pathname to the file they want to backup
		echo Please enter the complete pathname of the file that you would like to backup.
		echo Remember you are in:
		pwd

		# Read in the filename
		read FILETEXT
		
		# If statement to make sure the file is available and is a file not a directory
		# Otherwise give an error then ask again for a path
		if [ -f "$FILETEXT" ]; then
			echo You are going to backup the selected file:
			echo "$FILETEXT"
			echo The file will be backed up to the "wp" folder
			sleep 3
		else
			echo That is an incorrect path,
			echo please check the path and file,
			echo then enter the pathname again
			read FILETEXT
		fi

		# Execute the backup with arguments czf
		tar -cf $BackupWp $FILETEXT

		# If statement to see if the tar statement failed or succeded
		# If failed give an error and return to Backup Menu
		if [ $? == 0]; then
			echo Backup has been successful		
			sleep 3
		else
			echo Your backup could not be completed, a problem occured..
			sleep 3
		fi
		;;

	'b')	clear
		echo Backup of Spreadsheet Document
		sleep 2

		echo Please enter the complete pathname of the file that you would like to backup.
		echo Remember you are in:
		pwd

		read FILESPREAD

		if [ -f "$FILESPREAD" ]; then
			echo You are going to backup the selected file:
			echo "$FILESPREAD"
			echo The file will be backed up to the "ss" folder
			sleep 3
		else
			echo That is an incorrect path,
			echo please check the path and file,
			echo then enter the pathname again
			read FILESPREAD
		fi

		tar -czf $BackupSs $FILESPREAD

		if [ $? == 0 ]; then
			echo Backup has been successful
			sleep 3
		else
			echo Your backup could not be completed, a problem occured..
			sleep 3
		fi
		;;

	'd')	clear
		echo Backup of Picture
		sleep 2

		echo Please enter the complete pathname of the file that you would like to backup.
		echo Remember you are in:
		pwd

		read FILEPIC

		if [ -f "$FILEPIC" ]; then
			echo You are going to backup the selected file:
			echo "$FILEPIC"
			echo The file will be backed up to the "pics" folder
			sleep 3
		else
			echo That is an incorrect path,
			echo please check the path and file,
			echo then enter the pathname again
			read FILEPIC
		fi

		tar -czf $BackupPic $FILEPIC

		if [ $? == 0]; then
			echo Backup has been successful
			sleep 3
		else
			echo Your backup could not be completed, a problem occured..
			sleep 3
		fi
		;;

	'c')	clear
		;;

	*)	clear 
		echo Please try again select 1, 2, 3 or 4 only
		echo Press enter to continue
		read -n 1
		;;
	

;;

'2')	clear 
	echo ******************************************************************
	echo				Restore
	echo ******************************************************************
	echo
	echo 

;;

*)

;;

Thanks again :)

Stephen
 
You have this:
Code:
# Begin while statement
while true;
do

and this:
Code:
'1')	# Begin another while statement
	while true;
	do

but no 'done' statements. There may be other unmatched loops or conditionals. Those are just the ones I saw easily.

You would benefit from using shell functions. It would modularize things a lot better.
 
Got the first fault fixed now. Thanks chown :) was appreciated.

The script now runs quite well except when I go to create the backup it gives me the error:

That i must remove the leading / from the member file.

But if I do that then my test to see if it is a file fails because it needs the leading /. Is there any way to solve this? I should say the tar command still completes though.

And about using functions, I would rather just keep it as simple as possible just now until after I have it working then ill change it.

Thanks,

Stephen
 
The script now runs quite well except when I go to create the backup it gives me the error:

That i must remove the leading / from the member file.

You should read the man page for 'tar'. Carefully. Then work out what this means:
Code:
tar -czf "$TAROUT" -C / ./"$ABSPATHNAME"

Also, your invocations of the tar command don't quote the variables. This could cause problems if any value has embedded spaces or other things that might be misinterpreted by the shell.


Your use of tar may lose data. I don't know if tar preserves resource-forks, Finder metadata, and extended attributes. These may be important (or even critical) to recovering the original file. I recommend the 'ditto' command instead.


My purpose in suggesting functions is that it might help you make it work sooner by reducing the amount of code you have to write and test. The code would be simpler and a lot smaller if you defined a few functions.

Right now, there's a lot of duplicated code (very similar, or even identical), and it's hard to see the overall structure. If you don't know how to define functions, this is a good opportunity to learn. It's really not that hard, and it pays off pretty easily.


You have a bug whenever your first prompt for a file to backup is not a file. The second input is always accepted, even if it isn't a file or doesn't exist. You need a loop rather than a simple if/else (loop until the input is a file or user cancels).

This is also a bug:
Code:
	echo "c) Backup picture"
	echo
	echo "d) Return to Main Menu"

Code:
	'd')	clear
		echo Backup of Picture
...		;;

	'c')	clear
		;;
 
Thanks chown, i have changed my script into different functions and it does look surprisingly cleaner.

But the only thing is now, in my new function i pass in the choice selected and if it is a certain value I want it to return to the main code and then out of the case statement, this works.

But I also want to return out of the function if the user wishes to cancel, the way I am doing this just now is:

Code:
if [ "$1" == "d" ]; then
return 1

...

if [ $INPUT == "quit" ]; then
return 3

and in the main function I have after the call to my other function:

Code:
if [ "$?" -eq "1" ]; then
		clear
		x=1
	elif [ "$?" -eq "2" ]; then
		clear
		echo You must select between a, b, c and d
		echo Please try again
		sleep 2	
	elif [ "$?" -eq "3" ]; then
		clear
		echo You canceled the backup
		echo You will return to the backup menu
		sleep 2
	else
		echo Backup Succeeded
		sleep 2	
	fi

The thing is if the user quits e.g. $? to be 1 then it works fine but with the other returns it always does the else part but never the elif part it should. I looked on google before posting and my way seems as though it is the correct way, is there perhaps something I am doing wrong or am I just not understanding function returns in bash scripts?

Thanks,

Stephen
 
Thanks chown, i have changed my script into different functions and it does look surprisingly cleaner.

But the only thing is now, in my new function i pass in the choice selected and if it is a certain value I want it to return to the main code and then out of the case statement, this works.

Post all your code. Without all the code, there's not enough context to debug it.


Code:
if [ "$?" -eq "1" ]; then
		clear
		x=1
	elif [ "$?" -eq "2" ]; then
		clear
		echo You must select between a, b, c and d
		echo Please try again
		sleep 2	
	elif [ "$?" -eq "3" ]; then
		clear
		echo You canceled the backup
		echo You will return to the backup menu
		sleep 2
	else
		echo Backup Succeeded
		sleep 2	
	fi

The thing is if the user quits e.g. $? to be 1 then it works fine but with the other returns it always does the else part but never the elif part it should. I looked on google before posting and my way seems as though it is the correct way, is there perhaps something I am doing wrong or am I just not understanding function returns in bash scripts?

$? is always the exit status of the most recent command. Every command, builtin, or function affects the value of $?. Every 'echo' and 'sleep' and so on changes its value. Even the [ that tests the value affects $? (read 'man test'). For example, contrast the following outputs:

Code:
echo $?; [ "" ] ; echo $?
echo $?; [ "x" ]; echo $?

If you intend to refer to a specific value of $? at a specific point in time, e.g. immediately after your function returns, then you need to assign $? to a specific variable:
Code:
funStatus ="$?"
then use "$funStatus" instead of "$?" to evaluate the different status values returned by the function.
 
Heres my code, all works except the returns:

Code:
#!/bin/bash
# Stephen Ross's Backup Script

RestoreTo=/Users/rosstephen/Documents/

Backup()
{
	if [ "$1" == "a" ]; then
		TAROUT="/Users/rosstephen/Documents/wp/Archive_$(date '+%d.%m.%y:%H:%M').tgz"
	elif [ "$1" == "b" ]; then
		TAROUT="/Users/rosstephen/Documents/ss/Archive_$(date '+%d.%m.%y:%H:%M').tgz"
	elif [ "$1" == "c" ]; then
		TAROUT="/Users/rosstephen/Documents/pics/Archive_$(date '+%d.%m.%y:%H:%M').tgz"
	elif [ "$1" == "d" ]; then
		return 1
	else
		return 2
	fi

	clear

	x=0	

	while [ "$x" -eq "0" ]; do

	echo Please enter the complete pathname of the file that you would like to backup.
	echo Remember to add /username/documents at the start

	read FILETEXT

	if [ $FILETEXT == "quit" ]; then
		return 3
	fi

	if [ -f $FILETEXT ]; then
		echo You are going to backup the selected file:
		echo "$FILETEXT"
		x=1
		sleep 3
	else
		echo That is an incorrect path,
		echo please check the path and file,
		echo then enter the pathname again
		sleep 2
		clear
	fi

	done

	clear
	echo The backup will now proceed
	tar -czf "$TAROUT" -C / ./"$FILETEXT"
	
	# If statement to see if the tar statement failed or succeded
	# If failed give an error and return to Backup Menu
	if [ $? == 0 ]; then
		echo Backup has been successful		
		sleep 3
	else
		echo Your backup could not be completed, a problem occured..
		sleep 3
	fi

	return 0
}

Restore()
{
	if [ "$1" == "a" ]; then
		RestorePath="/Users/rosstephen/Documents/wp/"
		cd /Users/rosstephen/Documents/wp
	elif [ "$1" == "b" ]; then
		RestorePath="/Users/rosstephen/Documents/ss/"
		cd /Users/rosstephen/Documents/ss
	elif [ "$1" == "c" ]; then
		RestorePath="/Users/rosstephen/Documents/pics/"
		cd /Users/rosstephen/Documents/pics
	elif [ "$1" == "d" ]; then
		return 1
	else
		return 2
	fi

	clear
	echo You are about to restore a file from a backup
	sleep 2

	x=0	

	while [ "$x" -eq "0" ]; do

	echo Listed below are any backups that are in the backup folder
	ls $RestorePath | grep *.tgz
	echo
	echo Please select the file you would like to restore

	read FILE

	if [ $FILE == "quit" ]; then
		return 3
	fi

	if [ -f $FILE ]; then
		echo You are going to restore the selected file:
		echo "$FILE"
		x=1
		sleep 3
	else
		echo That is an incorrect path,
		echo please check the path and file,
		echo then enter the pathname again
		sleep 2
		clear
	fi
	
	done

	Restore=$RestorePath$FILE
	echo $Restore
	sleep 3

	clear 
	echo The file will now be restored
	
	tar -xzf "$Restore"

	if [ $? == 0 ]; then
		echo "$FILE" has been restored
		sleep 2
	else
		echo There was an error during the restore
		sleep 2
	fi

	return 0
}


# Begin while statement
while true;
do

# User choice menu - Main Menu

	clear
	echo ----------------------------------------------------------------
	echo 				Backup and Restore
	echo ----------------------------------------------------------------
	echo Please select an option from 1-3:
	echo
	echo "1) Create a backup"
	echo
	echo "2) Restore a file from a backup"
	echo
	echo "3) Exit system"
	echo

# Read user input
read USERCHOICE

# Begin the case statement
case $USERCHOICE in


'1')	x=0
	# Begin another while statement
	while [ "$x" -eq "0" ];
	do
	
	# User choice menu - Backup Menu

	clear
	echo ------------------------------------------------------------------ 
	echo                           Backup
	echo ------------------------------------------------------------------
	echo Please select an option 1-4:
	echo
	echo "a) Backup text document"
	echo
	echo "b) Backup spreadsheet document"
	echo
	echo "c) Backup picture"
	echo
	echo "d) Return to Main Menu"
	echo
	
	# Read user input
	read USERCHOICE2
	
	clear

	Backup $USERCHOICE2

	if [ "$?" -eq "1" ]; then
		clear
		x=1
	elif [ "$?" -eq "2" ]; then
		clear
		echo You must select between a, b, c and d
		echo Please try again
		sleep 2	
	elif [ "$?" -eq "3" ]; then
		clear
		echo You canceled the backup
		echo You will return to the backup menu
		sleep 2
	else
		echo Backup Succeeded
		sleep 2	
	fi

	done
;;

'2')	x=0
	# Begin another while statement
	while [ "$x" -eq "0" ];
	do
	
	# USer choice menu - Restore Menu

	clear
	echo ------------------------------------------------------------------ 
	echo                           Restore
	echo ------------------------------------------------------------------
	echo Please select an option 1-4:
	echo
	echo "a) Restore text document"
	echo
	echo "b) Restore spreadsheet document"
	echo
	echo "c) Restore picture"
	echo
	echo "d) Return to Main Menu"
	echo
	
	# Read user input
	read USERCHOICE2
	
	clear

	Restore $USERCHOICE2

	if [ "$?" -eq "1" ]; then
		clear
		x=1
	elif [ "$?" -eq "2" ]; then
		clear
		echo You must select between a, b, c and d
		echo Please try again
		sleep 2	
	elif [ "$?" -eq "3" ]; then
		clear
		echo You canceled the restore
		echo You will return to the restore menu
		sleep 2
	else
		echo Restore Succeeded
		sleep 2	
	fi

	done
;;

'3')	clear
	break
;;

*)	clear
	echo Sorry try again, select 1, 2 or 3 only
	echo press enter to continue
	read -n 1

;;
esac
done

exit

And so if i was to do:

Code:
return_val="$?"
return return_val

And then done the if statement on the value of that it should work?

And finally starting to understand scripting a but better thanks :)

Stephen
 
And so if i was to do:

Code:
return_val="$?"
return return_val

And then done the if statement on the value of that it should work?

I don't know what "And then done the if statement" means. There are several 'done' and 'if' statements.

You should be able to think this through and work it out yourself. If you can't think it through, then run an experiment and see what happens.

First, it would have to be 'return $return_val', for what should be obvious reasons.

Second, where are you suggesting that your code sequence be placed? If you mean "at the end of the Backup function", then think that through and work out what effect it should have.

This is where I meant:
Code:
	Backup "$USERCHOICE2"
	[B]return_val="$?"[/B]

	if [ [B]"$return_val" -eq "1"[/B] ]; then
		clear
		x=1
	elif [ [B]"$return_val" -eq "2"[/B] ]; then
        [I]...etc...[/I]

Note that I have quoted the parameter to the Backup function for safety. You have other places where unquoted parameters are used. You need to get in the habit of quoting things when needed or your scripts may become dangerous if a parameter containing a space is used.

You could also use a 'case' statement instead of an if/elif chain. This would remove the need for a separate return_val variable. In fact, many of your if/elif chains could be done by 'case' statements.
 
Thanks Chown for all your help, if there is anything you need help with in the future I would be glad to return the favour.

Stephen
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.