assistance on bash script for copying files - linux

I'm new to linux and to bash programming/scripting as well.
Anyhow, I wanted to make a bash script that will do a few things:
will get input on which files to copy
will get the dest folder
will ask wether to copy or move
will do the desired operation
will ask at the end if to continue for another action or not
Now, as for parts 2,3,5 I'm ok but part 1 is kinda problematic.
So, here is the script and I hope that you could enlighten me on where I am wrong and why :)
#! /bin/bash
#beginning
clear
f=1
Beginning()
{
echo "HELLO $USER , THIS PROGRAM WILL COPY THE FILES YOU WANT TO YOUR DESIRED DESTINATION DIRECTORY"
echo -n "please enter the filname/s you want to copy (up to 6 files at a time): ";
echo
EnteringF
}
EnteringF()
{
echo " filename$f : ";
read cop$f
Confirm
}
Confirm()
{
echo "do you wish to copy another file (y/n)?";
read ans
if [ "$ans" = "y" ] || [ "$ans" = "Y" ]; then
f=$[sum=$f+1]
EnteringF
elif [ "$ans" = "n" ] || [ "$ans" = "N" ]; then
Destination
else
echo " invalid choice please try again "
Confirm
fi
}
Destination()
{
echo -n "now please enter the destination folder:";
read dest;
CopyMove
}
CopyMove()
{
echo -n "Do you want to copy or move the files/s? please enter c/m? ";
read choice;
if [ "$choice" = "c" ] || [ "$choice" = "C" ]; then
cp "$cop$f" "$dest";
echo "copied successfully"
UseAgain
elif [ "$choice" = "m" ] || [ "$choice" = "M" ] ; then
mv [ "$files" + "$f" ] "$dest"
echo "moved successfully"
UseAgain
else
echo " invalid choice please try again ";
CopyMove
fi
}
UseAgain()
{
echo "Do you want to use the program again y/n?";
read confirm
if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
Beginning
UseAgain
elif [ "$confirm" = "n" ] || [ "$confirm" = "N" ]; then
End
else
echo "invalid choice please try again"; UseAgain
fi
}
End()
{
clear
echo "THANK YOU $USER FOR USING THIS PROGRAM :-)"
}
Beginning
Now my main problem is that no data is recorded to cop variable, and therefore cp has nothing to copy.
Maybe I should use some other loop, but I still don't know how to use the others.

You'd want to use an array. I've rewritten some parts of your code:
#!/bin/bash
clear
f=0
cop=()
abort() {
echo >&2 "Something went wrong ($#)."
echo >&2 "Do you have a banana jammed in the keyboard?"
exit 1
}
Beginning() {
echo "HELLO $USER , THIS PROGRAM WILL COPY THE FILES YOU WANT TO YOUR DESIRED DESTINATION DIRECTORY"
echo "please enter the filename/s you want to copy:"
EnteringF
}
EnteringF() {
local i=$((${#cop[#]}+1))
IFS= read -r -e -p " filename$i: " f || abort "EnteringF"
cop+=( "$f" )
Confirm
}
Confirm() {
local ans
read -e -p "do you wish to copy another file (y/n)? " ans || abort "Confirm"
if [[ "${ans,,}" = y ]]; then
EnteringF
elif [[ "${ans,,}" = "n" ]]; then
Destination
else
echo " invalid choice please try again "
Confirm
fi
}
Destination() {
IFS= read -r -e -p "now please enter the destination folder: " dest || abort "Destination"
CopyMove
}
CopyMove() {
read -r -e -p "Do you want to copy or move the file/s? please enter c/m? " choice || abort "CopyMove"
if [[ "${choice,,}" = c ]]; then
if cp -v -- "${cop[#]}" "$dest"; then
echo "copied successfully"
else
abort "cp"
fi
UseAgain
elif [[ "${choice,,}" = m ]] ; then
if mv -v -- "${cop[#]}" "$dest"; then
echo "moved successfully"
else
abort "mv"
fi
UseAgain
else
echo " invalid choice please try again "
CopyMove
fi
}
UseAgain() {
read -e "Do you want to use the program again y/n? " confirm || abort "UseAgain"
if [[ "${confirm,,}" = y ]]; then
Beginning
UseAgain
elif [[ "${confirm,,}" = "n" ]]; then
End
else
echo "invalid choice please try again";
UseAgain
fi
}
End() {
clear
echo "THANK YOU $USER FOR USING THIS PROGRAM :-)"
}
Beginning
I'm not even sure it works, when I tried to run it I had a black screen with a scary prompt asking me what file I wanted to copy or move. I was expecting a pony or something really cool like a cat playing piano. But no. I didn't know what file I wanted to move, actually. I'm not even sure I wanted to move a file. If I had wanted to move a file, I would have used mv directly. I've used a few bashisms for you to dig.
Regarding your question about the variable cop, I used an array, so all the problems are gone at once!
More importantly, there's a huge design flaw in your program: recursion! it's terrible. You're stacking at each step, never releasing the stack. You should really think your design again! Look: if you call your program lol_pony_cat, and if you type this in a terminal:
yes '42' | ./lol_pony_cat
you'll soon obtain
Segmentation fault
That's because:
We start in Beginning
We go in EnteringF and we're prompt for a file name: we enter 42
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so
We go in Confirm and we're prompt for y/n, but we answer an invalid 42, so...
like this until we reach a stack overflow.
Good luck.

Related

Bash script that allows one word as user input

Made a script that the user gives a "parameter" and it prints out if it is a file, directory or non of them. This is it :
#!/bin/bash
read parametros
for filename in *
do
if [ -f "$parametros" ];
then
echo "$parametros is a file"
elif [ -d "$parametros" ];
then
echo "$parametros is a directory"
else
echo " There is not such file or directory"
fi
exit
done
Altough i want the user to be allowed to give only one word as a parameter. How do i make this happen ? (For example if user press space after first word there would be an error message showing "wrong input")
#!/bin/bash
read parametros
if [[ "$parametros" = *[[:space:]]* ]]
then
echo "wrong input"
elif [[ -f "$parametros" ]]
then
echo "$parametros is a file"
elif [[ -d "$parametros" ]]
then
echo "$parametros is a directory"
else
echo " There is not such file or directory"
fi
See http://mywiki.wooledge.org/BashFAQ/031 for the difference between [...] and [[...]].
You have to use the $#. It gives the number of the parameters.
The code will be something like:
if [ "$#" -ne 1 ]; then
printf 'ERROR!\n'
exit 1
fi
First, I'm curious why you want to restrict to one word - a file or directory could have spaces in it, but maybe you are preventing that somehow in your context.
Here are a few ways you could approach it:
Validate the input after they enter it - check if it has any spaces, eg: if [[ "parametros" == *" " ]]; then...
Get one character at a time in a while loop, eg with: read -n1 char
Show an error if it's a space
Break the loop if it's 'enter'
Build up the overall string from the entered characters
1 is obviously much simpler, but maybe 2 is worth the effort for the instant feedback that you are hoping for?

How to solve the Bash error "syntax error near unexpected token"?

I am receiving an error within CentOS saying
'line 7: syntax error near unexpected token `then' and 'syntax error: unexpected end of file'
The point of this code is to ask a user for a filename and then either copy move or delete the file based off what they pick.
echo "Please enter the file name you wish to alter: "
read filename
if [ -f $filename ]; then
echo "Please enter either C, M, or D to copy, move or delete the file: "
read op
if [ "$op" = "C" ] || [ "$op" = "c" ]; then
echo "Please enter the destination directory in which you wish to copy to$
read dest
cp $filename $dest/$filename
echo "Complete"
elif [ "$op" = "M"] || [ "$op" = "m" ]; then
echo "Please enter the destination directory in which you wish to move to$
read dest
mv $filename $dest/$filename
echo "Complete"
elif [ "$op" = "D"] || [ "$op" = "d" ]; then
rm -i $filename
echo "Complete"
else "$filename does not exists try again."
fi
The third echo command has an unterminated string literal:
echo "Please enter the destination directory in which you wish to copy to$
Perhaps you wanted to write this instead:
echo "Please enter the destination directory in which you wish to copy to:"
The fifth echo command has the same problem.
Also, this statement is not valid:
else "$filename does not exists try again."
Perhaps you wanted to write this instead:
else
echo "$filename does not exists try again."
Also, there is no fi corresponding to the first if statement.
Also, the syntax [ "$op" = "M"] is invalid. You must have a space before the ] character, like this: [ "$op" = "M" ].
You have the same problem again in [ "$op" = "D"].
On line 7, you are closing your brackets too fast:
Instead of:
if [ "$op" = "C"] || ["$op" = "c" ]; then
you should have:
if [ "$op" = "C" || "$op" = "c" ]; then

How to create a normal running program? Because my program is run eternaly and wont stop

My English is very bad, but i'm try to explain my problem.
I want to create a small program on bash in which the user will have to guess the numbers. But my program has no end.
I'm novice on bash scripting, but i try to get better everyday.
I'm using CentOS 7. I go to /usr/bin/local and create some file, give him chmod +x and open with gedit:
#!/usr/bin/bash
#This script should ask us our name and play the game "Guess the Number" with us.
echo "What is your name?"
read name
echo "Hello $name"
echo "I want to play $ name with you, you have to guess the number from 1 to 10)"
echo "Are you ready?"
read rdy
answer=$(( answer = $RANDOM % 10 ))
read -p "Enter your number: " variant
while [ $answer != $variant ]; do
if [ $answer -gt $variant ]; then
echo "Your number is bigger, try again"
elif [ $answer -lt $variant ]; then
echo "Your number is smaller, try again"
continue
fi
done
eternal "Your number is smaller/bigger"
until you press ctrl+c
What I need to do, please help. I know non amateurs don't likes novices but i need your help, show me my mistake, and i can get better. Thanks!
#!/bin/bash
echo "What is your name?"
read name
echo "Hello $name"
echo "I want to play with you, you have to guess the number from 1 to 10"
answer=$(( $RANDOM % 10 ))
while true
do
read -p "Enter your number: " variant
if [ "$answer" -gt "$variant" ]; then
echo "The number is bigger, try again"
elif [ "$answer" -lt "$variant" ]; then
echo "The number is smaller, try again"
else
break;
fi
done
echo "Yes, the answer was ${answer}"
You call
read -p "Enter your number: " variant
before the while loop.
Inside the loop you never change the variant, so the original value is re-used in the while condition. For Eternity.
You can start with variant=-1 and move the readinside the loop or do something like #xiawi.

How to read two input values in bash?

I am writing a bash script which takes multiple user inputs. Before the script will take any action, I want to ensure that all values have been added by a user.
#/bin/bash
read -p "Please enter the domain Name: " domain
read -p "Please Enter path where you want to save your result: " path
if [[ -z "$domain" && "$path"]]; then
echo "You have not entered the Domain Name"
exit 1
else
echo "Do Something Here"
fi
I have checked with 1 user input, working fine, but when trying with 2 user inputs, I am getting an error.
./test.sh: line 5: unexpected token `;', conditional binary operator expected
./test.sh: line 5: syntax error near `;'
./test.sh: line 5: `if [[ -z "$domain" && "$path"]]; then'
Thanks!
Because you're using the [[ double brackets, you can use || to test if either of your conditions is true. In this case, your code would look like this:
#!/usr/bin/env bash
read -p "Please enter the domain Name: " domain
read -p "Please Enter path where you want to save your result: " path
if [[ -z "$domain" || -z "$path" ]]; then
echo "Either you have not entered the Domain Name, or you have not entered the path."
exit 1
else
echo "Do Something Here"
fi
Note that spaces around the brackets are necessary.
As others have pointed out, errors should be specific, so you should consider something like this:
if [[ -z "$domain" ]]; then
echo "You have not entered the Domain Name"
exit 1
elif [[ -z "$path" ]]; then
echo "You have not entered the path"
exit 1
fi
echo "Do something here"
It's a bit more verbose but gives the user more specific feedback.
You are getting syntax error because you forgot to put a space between "$path" and ] (bash uses spaces as delimiters).
If you want to fail when at least one condition is wrong, you should use the || (OR) operator.
#/bin/bash
read -p "Please enter the domain name: " domain
read -p "Please enter the path where you want to save your result: " path
if [[ -z "$domain" ]] || [[ -z "$path" ]] ; then
echo "You didn't enter the domain name or the save path"
exit 1
else
echo "Do something here"
fi

Looping a Bash Shell Script

I'm pretty much brand new to linux, and I've written a simple bash shell script that asks a user for a number and then asks for another number and displays the sum and product of the numbers. I have no problems with this, but I'm wanting to loop the script.
For instances, I want to ask the user if they want to quit, and if they choose not to quit the script starts over and asks for two numbers again. If there's anyone out there who knows stuff about loops, could you help me out please? Thanks.
Here's my code:
#!/bin/bash
echo -n "Name please? "
read name
echo "enter a number."
read number1
echo "enter another number"
read number2
echo "Thank you $name"
let i=0
let i=$number1+$number2
let x=0
let x=$number1*$number2
echo "The sum of the two numbers is: $i"
echo "The product of the two numbers is: $x"
echo "Would you like to quit? Y/N? "
quit=N
while [ "$quit" = "Y" ]
do
clear
while ["$quit" != "Y" ]
do
echo "enter a number."
read number1
echo "enter another number"
read number2
echo "Thank you $name"
let i=0
let i=$number1+$number2
let x=0
let x=$number1*$number2
echo "The sum of the two numbers is: $i"
echo "The product of the two numbers is: $x"
echo "Would you like to quit? Y/N? "
#!/bin/bash
# Initialize quit so we enter the outer loop first time
quit="N"
# Loop while quit is N
while [ "$quit" = "N" ]
do
echo -n "Name please? "
read name
echo "enter a number."
read number1
echo "enter another number"
read number2
echo "Thank you $name"
let i=0
let i=$number1+$number2
let x=0
let x=$number1*$number2
echo "The sum of the two numbers is: $i"
echo "The product of the two numbers is: $x"
#reset quit - so we enter the inner loop first time
quit=""
#we want to repeat until quit is Y or N:
#while quit is not "Y" and quit is not "N"
while [ "$quit" != "Y" -a "$quit" != "N" ]
do
echo "Would you like to quit? Y/N?"
read quit
#Convert lower case y/n to Y/N
quit=`echo $quit | tr yn YN`
done
done
while [[ "$(read -p "Quit?" q;echo $q)" != "y" ]] ; do
echo okay, go on
done
Here is a quick example of loops:
#!/bin/env bash
let quit="N"
while [ $quit != "Y" ]; do
echo "To quit, enter Y:"
read quit
done
#!/bin/bash
function sumAndProd {
read -p "enter a number: " number1
read -p "enter another number: " number2
echo "Thank you $name"
sum=$((number1+number2))
prod=$((number1*$number2))
echo "The sum of the two numbers is: $sum"
echo "The product of the two numbers is: $prod"
}
read -p "Name please? " name
quit=N
while [[ "$quit" != Y ]]
do
sumAndProd
read -p "Would you like to quit? Y/N? " quit
done
This is more a code-review.
The main thing is, to put the repeated part in a function.
instead of i, x, you better use expressive names, maybe abbreviated like sum and prod.
if you follow an assignment (let a=0) with an assignment, without using your variable before, the first assignment is senseless.
The name of the user will not change - we need to ask for this just once.
while (cond) ; do {block} done # is a form of loop.
You can specify a prompt (-p) with read, so this will end in one instead of two lines.
per se, you will not find let very often. For arithmetic expressions, x=$((expression)) is far more common.
Since you don't reuse sum and prod, you don't even need a variable. Just echo The sum is $((number1+number2))
The easiest thing to do is to loop forever and break when the user quits:
while true
do
read -p "Continue to loop? " answer
[ "n" = "$answer" ] && break
done
echo "Now I'm here!"
The break command breaks you out of the current loop and continues right after the loop. No need for a flag variable.
By the way:
[ "n" = "$answer" ] && break
Is the same as:
if [ "n" = "$answer" ]
then
break
fi
Note the -p for the prompt in the read command. That way, you can prompt and read the variable at the same time. You can also use \c in echo statements to suppress the New Line, or use printf which doesn't do a NL:
read -p "What do you want? " wants #Prompt on the same line as the read
echo "What are your desires? \c" #Prompt on the same line as the read
read desires
printf "What are your hopes? " #Prompt on the same line as the read
read hopes
Hope this helps.
#!/bin/sh
while true
do
/var/www/bash/grep_ffmpeg.sh
sleep 15
done
loop with nohup

Resources