I am creating a bash script that will backup a directory specified by the user. At the moment when the program runs the user will see all the files on the screen being compressed and copied, is there a while to simply replace what the user sees with a simple progress bar?
#!/bin/bash
ROOT="/Users/Rory/Documents"
ROOT_EXCLUDE="--exclude=/dev --exclude=/proc --exclude=/sys --exclude=/temp --exclude=/run --exlucde=/mnt --exlcude=/media --exlude"
DESTIN="/USer/Rory/Documents"
if [ "$USER" != "root" ]; then
echo "You are not the root user"
echo "To use backup please use: sudo backup"
exit
fi
clear
BANNER1="************************************************"
BANNER2="********* Backup Menu **************************"
BANNER3 ="************************************************"
echo $BANNER1
echo $BANNER2
echo $BANNER3
echo $BANNER3
OPTIONS="BACKUP DESTINATION EXIT"
LIST="1)BACKUP 2)SET DESTINATION 3)EXIT"
select opt in $OPTIONS; do
if [ "$opt" = "EXIT" ]; then
echo "GOODBYE!"
clear
exit
elif [ "$opt" = "BACKUP" ]; then
echo "BACKING UP FILES..."
tar cvpfz $DESTIN/backup.`date +%d%m%y_%k%M`.tgz $ROOT $ROOT_EXCLUDE_DIRS
echo "BACKUP COMPLETE"
exit
elif [ "$opt" = "DESTINATION"]; then
echo "DESTINATION IS $DESTIN/backup.`date +%d%m%y_%k%M`.tgz "
echo "TO CHANGE ENTER THE NEW DESTINATION..."
echo "TO LEAVE IT AS IS JUST PRESS ENTER..."
read NEW_DESTIN
#IF GREATER THEN 0 ASSIGN NEW DESTINATION
if [ ${#NEW_DESTIN} -gt 0 ]; then
DESTIN = "$NEW_DESTIN"
fi
clear
echo $BANNER1
echo $BANNER2
echo $BANNER3
echo $LIST
else
clear
echo "BAD INPUT!"
echo "ENTER 1 OR 2..."
echo $LIST
fi
done
If you copy your files using rsync, you can get a progress bar using the --progress parameter.
rsync --progress ...
Related
This is the code, when I am trying to run it on Putty it comes up with a syntax error at the end of the code : unexpected end of file. I've been staring at this for a few hours and I cannot figure out what is wrong. There is a directory called assessment and it only has an empty text file named: file2.txt . I am running the script from the home directory that contains the assessment directory.
#Bash Command Menu
#!/bin/bash
#Creates the file needed in the choices
if [ [ ! -f assessment/file1.txt ] ]
then
touch assessment/file1.txt
fi
#Prints the welcoming message
echo "Greetings '$USER' , this is the menu"
#while loop menu
while [ [ $choice != "5" ] ]
do
#Shows the choices
echo "The choices are:"
echo "1. Delete the file: file1.txt"
echo "2. View the contents of file2.txt with wordcount and line numbers"
echo "3. View all the running processes"
echo "4. View all files and directories withing home"
echo "5. Exit menu"
echo -n "What is your choice?"
#Reads what the user inputs
read $choice
#Choice1 - Delete file1.txt or prompt an error if the file has already been deleted
if [ $choice == "1" ]
then
echo "Choice 1 picked!"
if [ [ -f assessment/file1.txt ] ]
then
rm assessment/file1.txt
echo "File deletion successfull"
else
echo "The file does not exist"
fi
fi
#Choice 2 - Prompt file2.txt with wordcount and line numbers
if [ $choice == "2" ]
then
echo "Choice 2 picked!"
echo "Opening file: file2.txt"
cat -n assessment/file2.txt
echo "Counting words.."
wc -w assessment/file2.txt
fi
#Choice 3 - Show running processes
if [ $choice == "3" ]
then
echo "Choice 3 picked!"
echo "All running processes"
ps -aux
fi
#Choice 4 - Show all files and directories in home
if [ $choice == "4" ]
then
echo "Choice 4 picked!"
echo "Displaying all files and directories"
ls -R $HOME
fi
done
#Printing the good bye message
echo "Exiting menu, have a great day!"
exit;
select_again_dir:
echo -e "\033[32m enter the name of the source file; \033[0m"
echo
ls
echo
read build_source_dir
if [ ! -d $build_source_dir ]
then
echo "Folder Not Found. Please select again;"
goto select_again_dir:
else
echo "folder exists"
fi
Hello,
If the source file cannot be found, I want it to re-enter a value.
Is there a function you can suggest instead of goto?
The standard way is a while loop. One way to avoid duplication of the input read:
echo -e "\033[32m enter the name of the source file; \033[0m"
while [ ! -d "$build_source_dir" ]; do
echo
ls
echo
read build_source_dir
echo "Folder Not Found. Please select again: "
done
echo "folder exists"
Just loop it. You can use break and continue to your favor.
while true; do
echo -e "\033[32m enter the name of the source file; \033[0m"
echo
ls
echo
read build_source_dir
if [ ! -d "$build_source_dir" ]
then
echo "Folder Not Found. Please select again;"
continue # not really needed, there is nothing below to happen
else
echo "folder exists"
break # jump out of the loop
fi
done
#!/bin/sh
VAR2=0
while [ $VAR2 -eq 0 ]: do
echo "Please choose one of the following options:"
echo "1. List the current running processes"
echo "2. Check the available free memory"
echo "3. List the disks/partitions"
echo "4. Check for hardware (PCI)"
echo "5. Check for package installation"
echo "6. Create multiple files"
echo "7. Remove multiple files"
echo "8. List the contents of the current directory"
echo "0. Exit"
read VAR1
if [ $VAR1 -eq 0 ]; then
VAR2=2
fi
if [ $VAR1 -eq 1 ]; then
$(top)
fi
if [ $VAR1 -eq 2 ]; then
$(free)
fi
if [ $VAR1 -eq 3 ]; then
$(df)
fi
if [ $VAR1 -eq 4 ]; then
echo "Insert the name of the hardware that you want to search:" read VARHARD $(sudo lspci | grep $VARHARD)
fi
if [ $VAR1 -eq 5 ]; then
echo "Insert the name of the package that you want to search:" read VARPACK $(rpm -qa | grep VARPACK)
fi
if [ $VAR1 -eq 6 ]; then
echo "Insert the base name of the files:" read VARFILE echo "Insert the amount of files you want:" read VARNUMB $(touch $VARFILE{0001..000$VARNUMB})
fi
if [ $VAR1 -eq 7 ]; then
echo "Insert a string to delete all files that contain it:" read VARDEL $(find -type f -name '*$VARDEL*' -exec rm {} \;)
fi
if [ $VAR1 -eq 8 ]; then
$(ls -la)
fi
echo "Press any key and enter to continue... "
read teste
done
So, when I try to run the script "sh script.sh", it gives me an error that says "Syntax error near unexpected token `token'"
Can someone explain the error to me please? I'm new on scripting.
Thanks!
You have two problems in your code, the first is the invocation of subshells where is not due (using $() ) and the second is a typo at the line 26 (you have if instead of fi). The following corrected code works:
#!/bin/bash
VAR2=0
while [ $VAR2 -eq 0 ]; do
echo "Please choose one of the following options:"
echo "1. List the current running processes"
echo "2. Check the available free memory"
echo "3. List the disks/partitions"
echo "4. Check for hardware (PCI)"
echo "5. Check for package installation"
echo "6. Create multiple files"
echo "7. Remove multiple files"
echo "8. List the contents of the current directory"
echo "0. Exit"
read VAR1
if [ $VAR1 -eq 0 ]; then
VAR2=2
fi
if [ $VAR1 -eq 1 ]; then
top
fi
if [ $VAR1 -eq 2 ]; then
free
fi
if [ $VAR1 -eq 3 ]; then
df
fi
if [ $VAR1 -eq 4 ]; then
echo "Insert the name of the hardware that you want to search:"
read VARHARD
sudo lspci | grep $VARHARD
fi
if [ $VAR1 -eq 5 ]; then
echo "Insert the name of the package that you want to search:"
read VARPACK
rpm -qa | grep VARPACK
fi
if [ $VAR1 -eq 6 ]; then
echo "Insert the base name of the files:"
read VARFILE
echo "Insert the amount of files you want:"
read VARNUMB
touch $VARFILE{0001..000$VARNUMB
fi
if [ $VAR1 -eq 7 ]; then
echo "Insert a string to delete all files that contain it:"
read VARDEL
find -type f -name '*$VARDEL*' -exec rm {} \;
fi
if [ $VAR1 -eq 8 ]; then
ls -la
fi
echo "Press any key and enter to continue... "
read teste
done
Why are you using the syntax $(top)? That will execute top to completion (it may be long running, and never end), and then evaluate the output as a command and attempt to execute it. Most likely, the output of top is not valid shell syntax. I'm not sure exactly which command is generating the syntax error related to token, but that's probably the source of your error. Instead of $(top), just write top. Same for all the other instances of $() in the script.
I'm writing a shell script to make a new save file for the game risk of rain. I'm trying to make it so that each section of the unlocks that are available, such as achievements, monster logs, artifacts, etc. can either be added all at once to the file, or the user will be able to pick which ones they want added. I am new to writing shell scripts and I am not quite sure why I am getting the error syntax error near unexpected token `}' when I run what I have so far of my script. If anyone could explain to me as to why I am getting the error, how to fix it, and/or how to improve my script, it would be greatly appreciated. Also I am on Mac OS X if that matters. Here is my script.
#!/bin/bash
mkdir ~/Desktop/ror_save_unlock_all
echo "This script takes ~/Library/Application Support/com.riskofrain.riskofrain/Save.ini and backs it up to ~/Desktop/ror_save_unlock_all/originalSave. It generates a new Save.ini that is built to your specifications, unlocking all items and achievements or just the ones you choose, and replaces the existing Save.ini with the new one." >> ~/Desktop/ror_save_unlock_all/README.txt
mkdir ~/Desktop/ror_save_unlock_all/originalSave
cp ~/Library/Application\ Support/com.riskofrain.riskofrain/Save.ini ~/Desktop/ror_save_unlock_all/originalSave/
cd ~/Desktop/ror_save_unlock_all
echo -n 'How would you like the new Save.ini to be built? Press 1 for all unlocks or 2 to customize.'
read text
if [ $text = "1" ]
then
{
echo "[Achievement]" >> EOF1
count=1
while [ $count -lt 55 ]
do
echo "acheivement${count}=\"2\"" >> EOF2
count=`expr $count + 1`
done
echo "[Record]" >> EOF3
count=1
while [ $count -lt 31 ]
do
echo "mons${count}=\"1\"" >> EOF4
count=`expr $count + 1`
done
count=1
while [ $count -lt 110 ]
do
echo "item${count}=\"1\"" >> EOF5
count=`expr $count + 1`
done
count=1
while [ $count -lt 10 ]
do
echo "artifact${count}=\"1\"" >> EOF6
count=`expr $count + 1`
done
cat EOF1 EOF2 EOF3 EOF4 EOF5 EOF6 > Save.ini
rm EOF1 EOF2 EOF3 EOF4 EOF5 EOF6
cp -force ~/Desktop/ror_save_unlock_all/Save.ini ~/Library/Application\ Support/com.riskofrain.riskofrain/Save.ini
echo "Original Save.ini successfully overwritten."
exit
}
elif [ $text = "2" ]; then
{
echo "You selected customize. Now we will build a custom Save.ini"
echo -n "Press 1 if you want to unlock all achievements, press 2 to continue without unlocking all achievements."
read text
if [ $text = "1" ]; then
{
echo "[Achievement]" >> EOF1
count=1
while [ $count -lt 55 ]
do
echo "acheivement${count}=\"2\"" >> EOF2
count=`expr $count + 1`
done
echo "All achievements successfully unlocked."
echo -n "Press 1 to make the Save.ini and replace the existing one with it and then exit, or press 2 to customize it further."
read text
if [ $text = "1" ]; then
{
cat EOF1 EOF2 > Save.ini
rm EOF1 EOF2
cp -force ~/Desktop/ror_save_unlock_all/Save.ini ~/Library/Application\ Support/com.riskofrain.riskofrain/Save.ini
echo "Original Save.ini successfully overwritten."
exit
}
elif [ $text = "2" ] then;
{
echo -n "Press 1 to unlock all monster logs, or press 2 to continue without unlocking all monster logs."
read text
if [ $text = "1" ]; then
{
echo "[Record]" >> EOF3
count=1
while [ $count -lt 31 ]
do
echo "mons${count}=\"1\"" >> EOF4
count=`expr $count + 1`
done
echo "All achievements successfully unlocked."
echo -n "Press 1 to make the Save.ini and replace the existing one with it and then exit, or press 2 to customize it further."
read text
}
}
}
}
Your script has some error:
- Line 93: elif [ $text = "2" ] then; should change to elif [ $text = "2" ]; then
- If command in bash must have fi to close a condition. You can refer to http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-6.html
Hope this help
Before deciding to write a script, you should have a basic understanding of the language in which you're writing. Even the most cursory reading of the documentation or any how-to pages would have told you the correct syntax for an if statement.
Beyond that, you have a number of inefficiencies in your script. The backtick operator starts a subshell, a new instance of bash, so this is not necessarily something you want to be doing 110 times in a loop.
Here are a couple of your bigger problems fixed. I'd suggest looking into functions to eliminate a lot of code repetition and conditional nesting.
#!/bin/bash
mkdir ~/Desktop/ror_save_unlock_all
echo "This script takes ~/Library/Application Support/com.riskofrain.riskofrain/Save.ini and backs it up to ~/Desktop/ror_save_unlock_all/originalSave. It generates a new Save.ini that is built to your specifications, unlocking all items and achievements or just the ones you choose, and replaces the existing Save.ini with the new one." >> ~/Desktop/ror_save_unlock_all/README.txt
mkdir ~/Desktop/ror_save_unlock_all/originalSave
cp ~/Library/Application\ Support/com.riskofrain.riskofrain/Save.ini ~/Desktop/ror_save_unlock_all/originalSave/
cd ~/Desktop/ror_save_unlock_all
read -n 1 -p 'How would you like the new Save.ini to be built? Press 1 for all unlocks or 2 to customize.' text
if [ $text = "1" ]
then
echo "[Achievement]" > Save.ini
for count in {1..54}; do
echo "acheivement${count}=\"2\"" >> Save.ini
done
echo "[Record]" >> Save.ini
for count in {1..30}; do
echo "mons${count}=\"1\"" >> Save.ini
done
for count in {1..109}; do
echo "item${count}=\"1\"" >> Save.ini
done
for count in {1..9}; do
echo "artifact${count}=\"1\"" >> Save.ini
done
cp -force ~/Desktop/ror_save_unlock_all/Save.ini ~/Library/Application\ Support/com.riskofrain.riskofrain/Save.ini
echo "Original Save.ini successfully overwritten."
exit
elif [ $text = "2" ]; then
echo "You selected customize. Now we will build a custom Save.ini"
read -n 1 -p "Press 1 if you want to unlock all achievements, press 2 to continue without unlocking all achievements." text
if [ $text = "1" ]; then
echo "[Achievement]" > Save.ini
for count in {1..54}; do
echo "acheivement${count}=\"2\"" >> Save.ini
done
echo "All achievements successfully unlocked."
read -n 1 -p "Press 1 to make the Save.ini and replace the existing one with it and then exit, or press 2 to customize it further." text
if [ $text = "1" ]; then
cp -force ~/Desktop/ror_save_unlock_all/Save.ini ~/Library/Application\ Support/com.riskofrain.riskofrain/Save.ini
echo "Original Save.ini successfully overwritten."
exit
elif [ $text = "2" ]; then
read -n 1 -p "Press 1 to unlock all monster logs, or press 2 to continue without unlocking all monster logs." text
if [ $text = "1" ]; then
echo "[Record]" >> Save.ini
for count in {1..30}; do
echo "mons${count}=\"1\"" >> Save.ini
done
echo "All monster logs successfully unlocked."
read -n 1 -p "Press 1 to unlock all monster logs, or press 2 to continue without unlocking all monster logs." text
if [ $text = "1" ]; then
#...
fi
fi
fi
fi
fi
I have an annoying issue that seems to cause and infinite loop and I can't work out why. If I call the following function, it keeps repeating the yes/no options infinitely down the screen until I crash out.
AuditUpload() {
clear
echo "Audit report generated successfully"
echo " "
echo "Do you wish to upload qhub_audit.csv? (1 = Yes/2 = No):"
sleep 1
select yn in "Yes" "No"; do
case $yn in
Yes ) AuditUploader; Auditvi; exit;;
No ) echo "Upload cancelled"; Auditvi; exit;;
esac
done
}
I put the sleep in to see if it would remedy the issue but it still does the same. This issue seems to be very intermittent and doesn't happen every time. This script is written in korn shell (ksh).
AuditUploader function:
AuditUploader() {
echo "Uploading qhub_audit.csv to $HOST..."
curl -v -T qhub_audit.csv -# ftp://xxxxxxxx:xxxxxxxxx#xxxxxxxxxxxxx.com/
if [ "$?" -ne "0" ]
then
echo "ERROR: Cannot upload qhubload.csv"
exit
else
clear
echo "qhub_audit.csv has been put on $HOST successfully"
tput cup 5 5
echo "Copy and paste this link into internet explorer to download:"
tput cup 7 5
echo "ftp://xxxxxxxx:xxxxxxxxx#xxxxxxxxxxxxx.com/qhub_audit.csv"
read LINK
fi
}
Auditvi function:
Auditvi() {
clear
echo "Do you wish to view qhub_audit.csv? (1 = Yes/2 = No):"
sleep 1
select yn in "Yes" "No"; do
case $yn in
Yes ) vi qhub_audit.csv; exit;;
No ) exit;;
esac
done
}
After a bit of playing around it looks like it was looping whenever the 'curl' command returned a specific error which stopped the kill $$ from working properly. I replaced kill $$ with exit 1 and amended the other functions accordingly. I also put in a contingency to use kermit in case the FTP failed. Anyway, this is what my code looks like now:
#########################################
# Upload quotehub audit report function #
#########################################
AuditUploader() {
echo "Uploading qhub_audit.csv to $HOST..."
curl -v -T qhub_audit.csv -# ftp://$USER:$PASSWD#$HOST/ -m 10
if [ "$?" -ne "0" ]
then
echo "ERROR: Cannot upload qhubload.csv via FTP"
if [ ${term} = "tty1A" ]
then
echo "Attempting to download to modems server..."
wermit -s qhub_audit.csv
if [ $? -ne 0 ]
then
echo "Cannot upload to modems either!"
echo "This file will have to be downloaded manually"
exit 1
else
clear
echo "qhub_audit.csv has been put on modems server successfully"
tput cup 5 5
echo "Copy and paste this link into START -> RUN to download:"
tput cup 7 5
echo "\\\\\\xxxxxxxx\download\general\qhub_audit.csv"
read LINK
fi
else
echo "Upload failed!"
exit 1
fi
else
clear
echo "qhub_audit.csv has been put on $HOST successfully"
tput cup 5 5
echo "Copy and paste this link into internet explorer to download:"
tput cup 7 5
echo "ftp://$USER:$PASSWD#$HOST/qhub_audit.csv"
read LINK
fi
}
#######################################################
# Function to prompt user to upload qhub audit report #
#######################################################
AuditUpload() {
clear
echo "Audit report generated successfully"
echo ""
echo "Do you wish to upload qhub_audit.csv? (y/n):"
read REPLY
case "$REPLY" in
Y) AuditUploader; Auditvi; exit;;
y) AuditUploader; Auditvi; exit;;
N) Auditvi; exit;;
n) Auditvi; exit;;
*) echo "invalid option";;
esac
}
######################################
# Function to view qhub audit report #
######################################
Auditvi() {
if [ "$?" -ne "0" ]
then
exit 1
else
clear
echo "Do you wish to view qhub_audit.csv? (y/n):"
read REPLY
case "$REPLY" in
Y) vi qhub_audit.csv; exit;;
y) vi qhub_audit.csv; exit;;
N) exit;;
n) exit;;
*) echo "invalid option"; Pause; Auditvi;;
esac
fi
}
Thanks again guys for all your help.