Create a script to backup a file or directory tree by making a zip of the file(s) and copying it $HOME/Backups. The zipfile name should include what it is backing up, and the date the file was created. The script should take a random number of arguments specifying what to backup. If it is not given at least one item to include in the backup, it should complain. Ive got most of it to work but im having issues with multiple files ie file1 file2 to backup at the same time
#!/bin/bash
clear
echo
echo "Use this script to backup files to your home/backups directory"
echo
ls -la
echo
echo "================================================================"
echo
echo -n "Input file(s)/dir to backup: " ; read filez
while [ "$filez" == "" ] ; do
echo -n "You didnt input a filename, try again: " ; read filez
done
while [ ! -e "$filez" ] ; do
echo -n "No such file/dir, try again: " ; read filez
while [ "$filez" == "" ] ; do
echo -n "You didnt input a filename, try again: " ; read filez
done
done
echo
echo "================================================================"
echo
echo -n "Input name of backup file you wish to create(date automatically included): " ; read filezname
while [ "$filezname" == "" ] ; do
echo -n "You didnt input a filename, try again: " ; read filezname
done
zip -r $HOME/backups/$filezname"_$(date +%F)" $filez
Personally, I'm a fan of bash scripts taking arguments right from the command line:
script arg1 arg2 arg3 ...
Bash takes arguments using the special array $#, and you can do arguments processing with shift. Something like this:
#!/bin/bash
filezname=$1
shift
filez=""
for file in "$#"
do
filez="$filez $file"
done
if [[ $filez == "" ]]
then
echo "Give me argz! Nom nom nom!"
exit 0
fi
# Do stuff
What this does is it takes the first argument, takes it as the name of the zip file, and then slurps the rest of the filenames you want to zip up into a big long space-separated string that you can play with.
Related
I am writing a script that needs to create a file if an argument is passed to he script.
If no argument is passed then it will ask for fileName but it needs to have default permission as -rwx- --- - ---.
I am using this command chmod a=-rwx to remove all the default permissions and then i am using chmod u=+rwx to get the desired permission as stated but it is not working.
Can anyone help please?
#!bin\bash
if [ $#==0 ]; then
echo "Please enter a file name?"
read fileName
if [ -f $fileName ]; then
echo "File already exist! Opening for Editing"
sleep 3
nano $fileName
else
echo "File created with the name $fileName"
echo "Opening $fileName for editing "
sleep 3
echo "#!bin\bash" >$fileName
nano $fileName
fi
elif [ -f $1 ]; then
echo "File already exists with the name $1"
echo "Opening for editing"
sleep 3
nano $1
else
fileName="$1"
chmod a=-rwx $fileName
chmod u=+rwx $fileName
echo "File created with the name $filename"
echo "Opening $fileName for editing "
echo "#!bin\bash" >$fileName
sleep 3
nano $1
fi
Your chmod syntax is incorrect. The operation is either = to set the mode to a specific value, + to add modes, or - to remove modes; you can't combine them with =+ and =-.
You can perform multiple operations on a single file by separating them with ,.
So it should be:
chmod go-rwx,u+rwx "$fileName"
Another problem:
if [ $#==0 ]
should be
if [ $# -eq 0 ]
Use -eq for numeric comparisons, and spaces are needed around operators in shell conditions.
Third problem: You're doing the chmod before you create the file. Put it after
echo "#!/bin/bash" >"$fileName"
Fourth problem: #!bin\bash should be #!/bin/bash.
Finally, remember to quote your variables, in case they contain spaces.
I am trying to execute a hallo_word.sh that is stored at ~/bin from this script that is stored at my ~/Desktop. I have made both scripts executable. But all the time I get the problem message. Any ideas?
#!/bin/sh
clear
dir="$PATH"
read -p "which file you want to execute" fl
echo ""
for fl in $dir
do
if [ -x "$fl" ]
then
echo "executing=====>"
./$fl
else
echo "Problem"
fi
done
This line has two problems:
for fl in $dir
$PATH is colon separated, but for expects whitespace separated values. You can change that by setting the IFS variable. This changes the FIELD SEPARATOR used by tools like for and awk.
$fl contains the name of the file you want to execute, but you overwrite its value with the contents of $dir.
Fixed:
#!/bin/sh
clear
read -p "which file you want to execute" file
echo
IFS=:
for dir in $PATH ; do
if [ -x "$dir/$file" ]
then
echo "executing $dir/$file"
exec "$dir/$file"
fi
done
echo "Problem"
You could also be lazy and let a subshell handle it.
PATH=(whatever) bash command -v my_command
if [ $? -ne 0 ]; then
# Problem, could not be found.
else
# No problem
fi
There is no need to over-complicate things.
command(1) is a builtin command that allows you to check if a command exists.
The PATH value contains all the directories in which executable files can be run without explicit qualification. So you can just call the command directly.
#!/bin/sh
clear
# r for raw input, e to use readline, add a space for clarity
read -rep "Which file you want to execute? " fl || exit 1
echo ""
"$fl" || { echo "Problem" ; exit 1 ; }
I quote the name as it could have spaces.
To test if the command exists before execution use type -p
#!/bin/sh
clear
# r for raw input, e to use readline, add a space for clarity
read -rep "Which file you want to execute? " fl || exit 1
echo ""
type -p "$fq" >/dev/null || exit 1
"$fl" || { echo "Problem" ; exit 1 ; }
I am pretty new to shell scripting . I am trying to write a script to check for logfile for errors (error strings are hardcoded), and i have to print the lines containing the error . i am able to write the logic but need pointers to read a file from user input.
Appreciate the help thanks.
Logic:
Accept the logfile patch from user
Check if the logfile is present or not
If present search the file for lines containing the error string (eg. Error, ORA)
Print the lines containing error strings , also write the output to a logfile
Read the log file from user
Set error strings
search="ERROR"
set a path for output file
outfile="file1.txt"
Execution logic
find "$mydir" -type f -name "$filename" |while read file
do
RESULT=$(grep "$search" "$file")
if [[ ! -z $RESULT ]]
then
echo "Error(s) in $file: $RESULT" >> "$outfile"
fi
done
I'm not sure what you mean with "need pointers to read a file from user input". I assume "pointers" are script arguments.
You can use this script:
#!/bin/bash
expected=outfile
for f in $#
do
if [ "$expected" = outfile ]; then
OUTFILE=$1
expected=search
elif [ "$expected" = search ]; then
SEARCH=$2
expected=files
elif [[ -f $f ]]; then
RESULT=`grep "$SEARCH" $f`
if [ -n "$RESULT" ]; then
echo -e "\n"
echo "Error(s) in "$f":"
echo $RESULT
echo -e "\n" >> $OUTFILE
echo "Error(s) in "$f":" >> $OUTFILE
echo $RESULT >> $OUTFILE
fi
fi
done
Invoke with:
scriptname outfile search files
where:
scriptname: is the name of file containing the script.
outfile: the name of the output file
search: the text to be searched
files: one or many file name or file patterns.
Examples (I assume the name of the script is searcherror and it is in the system path):
searcherror errorsfound.txt primary /var/log/*.log
searcherror moreerrors.txt "ORA-06502" file1.log /var/log/*.log ./mylogs/*
I have below script but I can't find the error. Somebody an help me ?
In concrete I split a big file in different then compress any file, move it and send by ftp rename destination filename.
Something not work :(
in line:
put ${file} ${7}.T${j}(+1)
I try to rename the file with (+1) ended new filename
Kind regards
#!/bin/bash
# configuration stuff
# ${1} absolute path file
# ${2} num_files
# ${3} output_filename
# ${4} ipMainframe ip to put files
# ${5} FTP username
# ${6} FTP password
# ${7} destination filename
if [ ! $# == 7 ]; then
#number of parameter different of two
echo "Number of parameter incorrect"
echo "Command use: LLP_split_gzip_sendFTPandTrigger.sh absolute_path_file number_of_pieces output_filename ipMainframe userFTP pwdFTP destinationFilename"
exit 1
fi
if [ -f ${1} ]; then
# If file exists
if [[ ${2} =~ ^[\-0-9]+$ ]] && (( ${2} > 0)); then
# if number of pieces is an integer > 0
#Remove old files
echo "home directory = $HOME"
CMD=`rm -f '"$HOME"/"$3"*'`
if [ $? != 0 ]; then
echo "Impossible to remove old files $home/llp_tmp* $home/"$3"* in home directory"
echo $CMD
fi
# Calculate line for every file splitted
total_lines=$(cat ${1} | wc -l)
((lines_per_file = (total_lines + ${2} - 1) / ${2}))
# Split the actual file, maintaining lines.
CMD=`split -l "$lines_per_file" "$1" "$HOME"/llp_tmp`
if [ $? != 0 ]; then
echo "SPLITTING FILE ERROR: problem to split file."
echo $CMD
exit 3
fi
#For every file splitted rename and zip it
i=1
for file in $HOME/llp_tmp*; do
CMD=`mv "$file" "$3"."$i"`
if [ $? != 0 ]; then
echo "Impossible to rename file"
echo $CMD
exit 5
fi
CMD=`gzip "$3"."$i"`
if [ $? != 0 ]; then
echo "Impossible to compress file $3.$i"
echo $CMD
exit 6
fi
i=`expr $i + 1`
done
ftp -n ${4} << EOF
j=1
user ${5} ${6}
for file in $3.*; do
put ${file} ${7}.T${j}(+1)
j=`expr $j + 1`
done
quit
else
echo "number of pieces second parameter must be more than 0."
exit 2
fi
else
echo "absolute path first paramater doesnt exist"
exit 1
fi
exit 0
You are not terminating your here document. When I run your script I get:
gash.sh: line 72: warning: here-document at line 54 delimited by end-of-file (wanted `EOF')
gash.sh: line 73: syntax error: unexpected end of file
ftp -n ${4} << EOF is the issue. Where is your here document?
The warning says it all, you don't have an EOF marker. Note that this MUST NOT BE INDENTED! The EOF must be in "column 0" and have no trailing characters, including whitespace.
Edit: It appears you want to use program constructs within a single FTP session - I don't know of a way of doing that in Bash. Perl has an easy to use FTP module where you can do it, simple example:
use strict;
use Net::FTP;
my $ftp = Net::FTP->new ("hostname");
$ftp->login ("username", "password");
$ftp->binary ();
for my $file (glob("$ENV{HOME}/llp_tmp*")) {
$ftp->put ($file);
}
$ftp->quit();
You don't need parentheses around +1.
Change it to:
put "${file}" "${7}.T${j}+1"
It's good practice to quote variables.
Another tip: Instead of j=`expr $j + 1`, you can simply use ((j++)).
I'm in the final stages of a project and need to create a script that will run an executable a given number of times with varying input. One of the inputs is a file kept in a separate folder from the executable.
Before doing anything, I want to check whether the file exists. There are two possible file inputs that can be given, so I need to compare them. The possible inputs are
execute cancer 9
execute promoter 9
where cancer and promoters are the datasets to be used in the program and 9 is the number of times the script loop has to execute.
Here's what I've come up with:
#!/bin/bash
#Shell script to execute Proj 4 requirements while leaving the folder
#structure alone separated.
file1= "Data/BC/bc80-train-1"
file2= "Data/Promoters/p80-train-1"
if [ "$1" == "cancer" ] then #execute command on the cancer dataset
echo "Executing on the cancer dataset"
if [ -f "$file1" ] then
echo "$file1 file exists..."
else
echo "$file1 file Missing, cancelling execution"
echo "Dataset must be in ../Data/BC/ and file must be bc80-train-1"
fi
elif [ "$1" == "promoter" ] then #execute on the promoter dataset
echo "Executing on the promoter dataset"
if [ -f "$file2"] then
echo "$file2 file exists..."
else
echo "$file2 file missing, cancelling execution"
echo "Dataset must be in ~/Data/Promoters/ and file must be p80-train-1"
fi
fi
The problem with this is it opens the files and outputs them to terminal, where each line ends in : command not found
I thought the -f and -e flags were used to check whether a file exists. So why is the file content being output to the terminal?
Drop the space to the right of = in:
file1= "Data/BC/bc80-train-1"
file2= "Data/Promoters/p80-train-1"
Also the keyword then should be on a line by itself or if on the same line as if should have a ; before it:
if [ condition ] ; then
...
fi
OR
if [ condition ]
then
...
fi
Your error messages mix ../Data/ and ~/Data/, but your file1 and file2 don't have either .. or ~ in their definitions:
file1= "Data/BC/bc80-train-1"
file2= "Data/Promoters/p80-train-1"
Remove the space after the = in file1= and file2=
Don't repeat yourself, use a function:
#!/bin/bash
checkfile() {
echo "Executing on the $1 dataset"
file="$2/$3"
if [ -f "$file" ] then
echo "$file file exists..."
else
echo "$file file Missing, cancelling execution"
echo "Dataset must be in $2 and file must be $3"
fi
}
case $1 in
cancer)
checkfile $1 Data/BC bc80-train-1
;;
promoter)
checkfile $1 Data/Promoters p80-train-1
;;
*)
echo "Error: unknown dataset. Use 'cancer' or 'promoter'"
;;
esac