having an issue with my bash script - linux

im writing a script that allows the user to create a backup of a file they choose by allowing them to input the file name. the file will then have backup followed by being date stamped at the end of it's name and saved on the home drive. but whenever i try to run it i get an error: cp: missing destination file operand after '_backup_2017_12_16'
here's my code:
title="my script 3"
prompt="Enter:"
options=("create a backup of a file")
echo "$title"
PS3="$prompt "
select opt in "${options[#]}" "Quit"; do
case "$REPLY" in
esac
cp "$filename""${file}_backup_$(date +%Y_%m_%d)"
done

Your case statement is currently empty. You need it to handle your chosen option
There needs to be a space between arguments: cp source dest
If you are using array for the options, you can also put Quit in there
If you choose the option to create a backup, you need to prompt the user to enter a filename. read command is used to get user input
Putting it all together, your script could look like this:
#!/usr/bin/env bash
options=("Backup" "Quit")
prompt="Enter: "
title="My script 3"
echo "$title"
PS3=$prompt
select opt in "${options[#]}"; do
case $opt in
"Backup")
IFS= read -r -p "Enter filename: " filename
cp -- "$filename" "${filename}_backup_$(date +%Y_%m_%d)" && echo "Backup created..."
;;
"Quit") break ;;
*) echo "Wrong option..." ;;
esac
done

Related

While loop to test if a file exists in bash script

I am trying to create a loop to prompt the user to create a file. If the file already exists, it will keep prompting the user until the user enters a file that does not exist. But can't seem to get it to work, anyone can help, please?
file3=/root/simulate/$filename
while true ; do
if [ ! -f "$file3" ]; then
read -p "Please enter a file name to create in simulate folder:" filename
touch /root/simulate/$filename
elif [ -f "$file3" ]; then
read -p "Please enter a different file name as $filename already exist:" filename
touch /root/simulate/$filename
break
else
touch /root/simulate/$filename
fi
done
filename variable is empty.
There are two way to fill in filename variable
filename variable can pass on shell script by export command.
ex) $export filename=newFile
if you execute shell script, shell is forking and execute new shell. new shell taken your mother shell's Environment variables
Push filename variable into shell script.
note: I picked second way and I changed path of $file3.
I fixed codes in block of elif to ask again if something goes wrong.
this is a code.
#!/bin/bash
filename=newFile
file3="./$filename"
while true ; do
if [ ! -f "$file3" ]; then
read -p "Please enter a file name to create in simulate folder:" filename
touch ./$filename
break
elif [ -f "$file3" ]; then
while true ; do
read -p "Please enter a different file name as $filename already exist:" filename
if [ ! -f "$filename" ]; then
touch ./$filename
break 2
fi
done
else
touch ./$filename
fi
done

Shell script to scp rpm to remote server and install it. Needs a variable to pass remote host name

I am attempting to write a sort of menu script which will achieve the below once executed:
Ask what user/password you are executing the script as.
Ask the remote server i.p. you want to scp files to.
Ask the directory where the files are stored locally.
Ask the directory where all the files are to be transferred to.
Copy all the files.
The first hurdle I have is getting the password stored as a variable within the menu. I think sshpass will be good for that. I would like to configure a menu like this:
title="Select example"
prompt="Pick an option:"
options=("A" "B" "C")
echo "$title"
PS3="$prompt "
select opt in "${options[#]}" "Quit"; do
case "$REPLY" in
1 ) echo "You picked $opt which is option $REPLY";;
2 ) echo "You picked $opt which is option $REPLY";;
3 ) echo "You picked $opt which is option $REPLY";;
$(( ${#options[#]}+1 )) ) echo "Goodbye!"; break;;
*) echo "Invalid option. Try another one.";continue;;
esac
done
But the menu would ask you for username, local directory of files, i.p. of remote server, remote server directory and then run the scp command it constructed.
Something like this:
password="your password"
username="username"
Ip="<IP>"
sshpass -p "$password" scp /<PATH>/final.txt $username#$Ip:/root/<PATH>
But I'm a bit confused as to how I can put that all of that together so that the menu gathers the required information and then executes the collected input so that it simply constructs an scp command to fire.
Can anyone offer any experience with this to aid me in the construction of the menu script?
Thanks!
You don't need a menu, just ask for each input sequentially.
read -p "Username:" username
read -s -p "Password:" password
read -p "Server IP:" ip
read -p "Local directory:" local
read -p "Remote directory" remote
sshpass -p "$password" scp "/$local/final.txt" "$username#$ip:/root/$remote/"
If you still need a menu here it is. I modified your script a bit to make it construct/print scp command while entering values one by one.
#!/bin/bash
title="Select example"
prompt="Pick an option:"
declare -A options # turn options to an associative array
options[1]='change user name'
options[2]='change user password'
options[3]='change remote host address'
options[4]='change path to source files'
options[5]='change destination path on remote server'
PS3="$prompt "
menu () { # wrap all this to a function to restart it after edition of an element
echo "$title"
select opt in "${options[#]}" "Quit"; do
case "$REPLY" in
1 ) read -p "${options[1]}: " user;;
2 ) read -sp "${options[2]}: " pass;; # read password with option -s to disable output
3 ) read -p "${options[3]}: " addr;;
4 ) read -p "${options[4]}: " from;;
5 ) read -p "${options[5]}: " dest;;
$(( ${#options[#]}+1 )) ) echo "Goodbye!" ; exit;;
*) echo "Invalid option. Try another one.";;
esac
clear # clear screen to remove inputs
printf "Creating scp command:\n"
# we don't want to show password, print *** if password set and 'password not set' if not
[[ $pass ]] && pass2='***' || pass2='[password not set]'
# text in [] will be printed if var is empty or not set, it's usefull to add default values to vars ${var:-default_value}
printf "sshpass -p $pass2 scp -r ${from:-[source not set]}/* ${user:-[user not set]}#${addr:-[host not set]}:${dest:-[destination not set]}/\n\n"
menu
done
}
clear # clear screen
menu # and start menu function
And here I've got a script with similar (but richer) functionality, please take a look.

Bash Validate User Input

I'm making a small program that lets the user write their name and then proceeds to create a folder with the name they typed. I have this:
#!/bin/bash
echo "Enter your name:"
read name
mkdir /home/mint/Desktop/$name
That's working perfectly fine but I was wondering if there's a way to validate the input so that my program will only accept letters of the alphabet. Any help will be greatly appreciated.
There are many many ways to do this:
while true; do
read -p "Enter your name: " name
case "$name" in
*[^A-Za-z]*) echo "Only letters are allowed" ;;
*) break ;;
esac
done
mkdir ~/Desktop/"$name"
You'll want to find a tutorial. There's one here: http://mywiki.wooledge.org/EnglishFrontPage
Or start here on Stack Overflow: https://stackoverflow.com/tags/bash/info
You can do this:
#!/bin/bash
echo "Enter your name:"
read name
if [[ "$name" =~ ^[a-zA-Z]+$ ]]; then
echo "Creating directory: /home/mint/Desktop/$name"
mkdir /home/mint/Desktop/$name
else
echo "Your directory name may only use letters. Please try again."
fi
That's using a regular expression that allows only lowercase a-z and capital A-Z letters.
Something like this ?
#!/bin/bash
echo "Enter your name:"
read name
name=$(tr -dc [:alpha:] <<<"$name" )
mkdir "/home/mint/Desktop/$name"

How to write a bash shell script which takes one argument (directory name)

How to write a bash shell script called 'abc' which takes one argument, the name of a directory, and adds the extension ".xyz" to all visible files in the directory that don't already have it
I have mostly written the code which changes the filenames inside the current directory but I can't get the script to accept an argument (directory name) and change the filenames of that directory
#!/bin/bash
case $# in
0) echo "No directory name provided" >&2 ; exit 1;;
1) cd "${1}" || exit $?;;
*) echo "Too many parameters provided" >&2 ; exit 1;;
esac
for filename in *
do
echo $filename | grep "\.xyz$"
if [ "$?" -ne "0" ]
then mv "$filename" "$filename.old"
fi
done
additional instructions include;
Within 'abc', use a "for" control structure to loop through all the non-hidden filenames
in the directory name in $1. Also, use command substitution
with "ls $1" instead of an ambiguous filename, or you'll descend into subdirectories.
EDIT: The top part of the question has been answered below, however the second part requires me to modify my own code according to the following instructions:
Modify the command substitution that's being used to create the loop values that will be placed into the "filename" variable. Instead of just an "ls $1", pipe the output into a "grep". The "grep" will search for all filenames that DO NOT end in ".xyz". This can easily be done with the "grep -v" option. With this approach, you can get rid of the "echo ... | grep ..." and the "if" control structure inside the loop, and simply do the rename.
How would I go about achieving this because according to my understanding, the answer below is already only searching through filenames without the .xyz extension however it is not being accepted.
Your description is a little unclear in places, so I've gone with the most obvious:
#!/bin/bash
# validate input parameters
case $# in
0) echo "No directory name provided" >&2 ; exit 1;;
1) cd "${1}" || exit $?;;
*) echo "Too many parameters provided" >&2 ; exit 1;;
esac
shopt -s extglob # Enables extended globbing
# Search for files that do not end with .xyz and rename them (needs extended globbing for 'not match')
for filename in !(*.xyz)
do
test -f && mv "${filename}" "${filename}.xyz"
done
The answer to the second part is this:
#!/bin/bash
for file in $(ls -1 "$1" | grep -v '\.old$'); do
mv "$file" "$file.old"
done
I got it from somewhere

Linux file deletion error

Every time I run this code I get the error File or directory doesn't exist. Why?
read -p "Enter the filename/path of the file you wish to delete : " filename
echo "Do you want to delete this file"
echo "Y/N"
read ans
case "$ans" in
Y) "`readlink -f $filename`" >>~/TAM/store & mv $filename ~/TAM/dustbin
echo "File moved" ;;
N) "File Not deleted" ;;
esac
When I enter the file name/directory exactly and triple check its right I still get this error, but the readlink part works.
Paraphrasing/summarizing/extending my answer for a similar question:
I doubt you really meant to use & instead of && in your script.
"File Not deleted" is not a valid command on any Linux system that I have used. Perhaps you are missing an echo there?
You have to fix your variable quotation. If the filename variable contains whitespace, then $filename is expanded by the shell into more than one arguments. You need to enclose it into double quotes:
mv "$filename" ~/TAM/dustbin
I do not see your script creating the ~/TAM/ directory anywhere...
You are missing an echo and one &&.
Use echo "`command`" to pipe the result string of commands. Alternatively, you may directly use the command without backticks and quotes, (not storing the result in a string), in which case you do not need an echo because the command will pipe its result to the next command.
The single & will run the preceding command in the background (async.). To check for return values and conditionally execute you need && and ||.
Here is a complete solution/example (incl. some more logging):
# modified example not messing the $HOME dir.
# should be save to run in a separate dir
touch testfile #create file for testing
read -p "Enter the filename/path of the file you wish to delete : " filename
echo "Do you want to delete this file: $filename"
echo "Y/N"
read ans
touch movedfiles #create a file to store the moved files
[ -d _trash ] || mkdir _trash #create a dustbin if not already there
case "$ans" in
Y) readlink -f "$filename" >> movedfiles && echo "File name stored" &&
mv "$filename" _trash && echo "File moved" ;;
N) echo "File Not deleted" ;;
esac
cat movedfiles #display all moved files

Resources