I am trying to make a bash script that gives the user options 1-5,with 5 being to exit. For option 2 I want the to be able to pass the file name as a argument for the file_size script but even when I catch the user input it still says the error message please enter a single file name as an argument. I am not sure why is doesn't pass it as a argument, Any help would be appreciated.
#!/bin/bash
# usage: ./menu_script
exitvar=false
while [ $exitvar = "false" ] # keep looping until exit equal true
do
echo -n "Enter a number 1 through 5, 5 to exit"
read number
case $number in
1) echo "Move empty files"
/home/student/move_empty;;
2) echo "Check file size"
echo -n "Enter a file name to check: "
read sourcefile
/home/student/file_size;;
3) echo "Option3";;
4) echo "File check rwx"
echo -n "Enter a file name to check: "
read sourcefile
if [ -e $sourcefile ] # does the source file exist?
then
echo $sourcefile "exists!"
fi
# find out if file has write permission or not
[ -w $sourcefile ] && W="Write = yes" || W="Write = No"
# find out if file has excute permission or not
[ -x $sourcefile ] && X="Execute = yes" || X="Execute = No"
# find out if file has read permission or not
[ -r $sourcefile ] && R="Read = yes" || R="Read = No"
echo "$sourcefile permissions"
echo "$W"
echo "$R"
echo "$X"
;;
5) echo "exit"
exitvar="true"
;;
*) echo "Invalid number try again"
;;
esac
done
At the option 2)
2) echo "Check file size"
echo -n "Enter a file name to check: "
read -r sourcefile
echo /home/student/file_size "$sourcefile";;
To see if the argument is being pass to /home/student/filesize
It would be nice and informative to show a menu with numbers alongside the option.
Or run subscripts with source or . this way subscripts will gain access to vars in main script
source /home/student/file_size
. /home/student/file_size
And use -p option for read to minimize echoes
read -r -p "Enter a file name to check: " sourcefile
Related
I'm currently creating a script to retrieve a set of lines from a file and will let users select any one of them to perform certain task.
Eg:
echo "my_files"
1) my_files1
2) my_files2
3) my_files3
...
n) my_filesN
I want to let the user select any one of these line and perform certain task based on the selection in shell script.
Perhaps you want to have something like the next menu:
#!/bin/bash
test -f "$1" || { echo "File \"$1\" can not be found."; exit 1; }
readarray -t options < "${1}"
# set the prompt used by select, replacing "#?"
PS3="Use a number to select a command or 'q' to cancel: "
stopmenu=
while [[ -z "${stopmenu}" ]]; do
select opt in "${options[#]}" ; do
if [[ ${REPLY} = q ]]; then
stopmenu=1
break
fi
if [[ ${#opt} -gt 0 ]]; then
echo "$opt"
source <(echo "${opt}")
fi
break
done
echo
done
You can give a filename with shell commands as an argument, something like menu myfile. The file with menu options can look like
echo "Hello world"
echo "Comment is allowed" # Just add text after a hash.
ls -l
echo "Value of xxx=[${xxx}]" # xxx can be filled in the next menu option
read -p "Enter value for xxx: " xxx # The variable xxx will be known in the menu
Read the filenames into an array with readarray.
Use the select built-in to display the list of files as a menu.
echo "Select a file":
readarray -t files list_of_files.txt
select file in "${files[#]}"; do
echo "You selected $file";
done
I am new to Linux bash scripting and I can't seem to find what I'm doing wrong. Here's my code. Entering number 2 and 3, after the prompt that I ask the user my code stops it doesn't continue to the IF ELSE statements. Thank you to those who will help!
#!/bin/bash
while true
do
clear
echo "Please enter one of the following options"
echo "1. Move empty files"
echo "2. Check file size"
echo "3. Which file is newer"
echo "4. File check rwx"
echo "5. Exit".
echo -e "Enter Choice:"
read answer
case "$answer" in
1) ./move_empty
exit 55 ;;
2) echo "Enter a filename"
read filename
if [ -f $filename ];
then ./file_size
fi
;;
3) echo "Enter first file:"
read filename
echo "Enter second file:"
read filename2
if [ ! -f "$filename" ];
then
echo "Supplied file name" $filename "does not exist";
if [ $filename" -nt $filename" ]; then
echo $filename "is newer"
exit 1fi
fi ;;
5) exit ;;
esac
done
If you have completed the check at ShellCheck.net, then you should have received:
$ shellcheck myscript
No issues detected!
If you didn't work it down to that point, you are not done. You have multiple quoting problems in your script and you compare $filename -nt $filename (which is always false). Small "attention to detail" issues that make a big difference. ShellCheck.net does a thorough job, but will not find logic issues, those are left to you. The cleanup of your quoting would look similar to:
#!/bin/bash
while true
do
clear
echo "Please enter one of the following options"
echo "1. Move empty files"
echo "2. Check file size"
echo "3. Which file is newer"
echo "4. File check rwx"
echo "5. Exit".
echo -n "Enter Choice: "
read -r answer
case "$answer" in
1) ./move_empty
exit 55
;;
2) echo -n "Enter a filename: "
read -r filename
if [ -f "$filename" ]
then
./file_size
fi
;;
3) echo -n "Enter first file: "
read -r filename
echo -n "Enter second file: "
read -r filename2
if [ ! -f "$filename2" ]
then
echo "Supplied file name $filename does not exist";
if [ "$filename" -nt "$filename2" ]; then
echo "$filename is newer"
exit 1
fi
fi
;;
5) exit
;;
esac
done
(note: you do not need echo -e as there are no backslash escaped characters to handle in your prompt, likely you intended -n to prevent the addition of a newline at the end of the prompt)
(also note: the use of clear, while fine for some terminals, will cause problems with others. Just be aware of the potential issue.)
If your then is on the same line with your conditional expression, e.g. if [ "$filename" -nt "$filename2" ]; then then a ';' is needed after the closing ']' to indicate a newline, otherwise, there is no need for a ';'.
Logic Problems
As discussed, the logic problems are not caught by ShellCheck and you must work though the code. It looks like you intended something like the following:
3) echo -n "Enter first file: "
read -r filename
echo -n "Enter second file: "
read -r filename2
if [ ! -f "$filename" ] || [ ! -f "$filename2" ]
then
echo "Supplied file '$filename' or '$filename2' does not exist";
exit 1
fi
if [ "$filename" -nt "$filename2" ]; then
echo "$filename is newer"
else
echo "$filename2 is newer"
fi
;;
You just have to take it line by line...
Look things over and let me know if you have further questions.
Modify your program so that if no matching name is found, a message is displayed: "Name 'xyz' not in directory". You could use an 'if' statement to check the value of $? to see if the grep command was successful (remember that '0' indicates success). If the grep is NOT successful, then echo the message (which includes the value of $name).
The original code was:
#!/bin/bash
name=$1
if [ "$name" = "" ]
then echo -n "Enter a name to search for: "
read name
fi
grep -I $name ~uli101/2017a/phonebook
I basically have to insert and IF statement into the program using the instructions above. I've tried many different things such as:
if [ $? = 1 ]
then echo -n "Name 'xyz' not in directory"
fi
but it is not accepting the answer. Pls help me out with this. Any help is appreciated.
This is working for me, try:
#!/bin/bash
name=$1
if [ "$name" = "" ]; then
echo -n "Enter a name to search for: "
read name
fi
grep -I $name phonebook
if [ $? = 1 ]; then
echo "Name '${name}' not in directory"
fi
Or you can change the last IF into:
grep -I $name phonebook && echo -n "Name not in directory"
Try this, it works for me.
#!/bin/bash
#
NAME=$1
if [ -z "${NAME}" ]; then
echo -n "Enter a name to search for: "
read NAME
fi
grep -I $NAME~uli101/2017a/phonebook
This code is that I want to give two directory and this code will look if these two directory contains two files that contains the same information, and asks me which file I want to delete .
I have written this code but I don't know how to write the code that will delete the file , please help
#!bin/bash
echo "give the first directory"
read firstdir
echo "give the second directory"
read seconddir
for i in ` ls $firstdir`
do
echo $i
t= `md5sum $firstdir/$i`
s= `md5sum $seconddir/$i`
if [ "$t" ! = "$s" ]
then
echo " of which directory will be eliminated? $i"
read direct
( here I want the code to delete the directory ex : delete direct/i )
fi
done
Replace:
echo " of which directory will be eliminated? $i"
read direct
( here I want the code to delete the directory ex : delete direct/i )
With:
echo "of which directory will be eliminated? $i:
1)$firstdir
2)$seconddir
"
read -p "(1/2)" direct
case $direct in
1)
rm -v $firstdir/$i
;;
2)
rm -v $seconddir/$i
;;
*)
echo "ERROR: bad value, 1 or 2 expected!" ; exit 1
esac
Ok, try this. I just made my own solution based on your requirements. I hope you like it. Thanks
#!/bin/bash
# check for a valid first directory
while true
do
echo "Please, enter the first directory"
read FIRST_DIR
if [ -d $FIRST_DIR ]; then
break
else
echo "Invalid directory"
fi
done
# check for a valid second directory
while true
do
echo "Please, give the second directory"
read SECOND_DIR
if [ -d $SECOND_DIR ]; then
break
else
echo "Invalid directory"
fi
done
for FILE in `ls $FIRST_DIR`
do
# make sure that only files will be avaluated
if [ -f $FILE ]; then
echo $SECOND_DIR/$FILE
# check if the file exist in the second directory
if [ -f $SECOND_DIR/$FILE ]; then
# compare the two files
output=`diff -c $FIRST_DIR/$FILE $SECOND_DIR/$FILE`
if [ ! $output ]; then
echo "Which file do you want to delete?
1)$FIRST_DIR/$FILE
2)$SECOND_DIR/$FILE
"
# read a choice
read -p "(1/2)" choice
# delete the chosen file
case $choice in
1)
rm -v $FIRST_DIR/$FILE
;;
2)
rm -v $SECOND_DIR/$FILE
;;
*)
echo "ERROR invalid choice!"
esac
fi
else
echo "There are no equal files in the two directories."
exit 1
fi
else
echo "There are no files to be evaluated."
fi
done
I'm fairly new to Linux and shell scripting.
My problem is, that the script should read 2 tokens from a file called "list" - using these tokens, it creates a user and depending on the second token, a sub folder. It does this just fine - but only once. Only ONCE. Is there a problem with my WHILE loop?
Here is a few sample lines from "list":
egyes n
kettes y
harmas y
Here's the script:
#!/bin/bash
echo " " >> /root/userpass.txt
most=$(date)
while read user rr; do
p1=${user:0:2}
p2=${user:3:4}
pass=$p1$RANDOM$p2
echo $user - $pass --" LÉTREHOZVA: "$most >> /root/userpass.txt
adduser $user > /dev/null
echo $user:$pass | chpasswd > /dev/null
uhome=/home/$user
if [ $rr=="y" ]; then
mkdir $uhome/rockandroll
chown $user $uhome/rockandroll
fi
mkdir $uhome/res-devres
chown $user $uhome/res-devres
ftpc=/etc/proftpd/proftpd.conf
echo "#"$1 >> $ftpc
echo "<Directory "$uhome"/res-devres/>" >> $ftpc
echo ' <Limit CDUP XCUP STOR LIST CWD XCWD STOU>' >> $ftpc
echo ' AllowAll' >> $ftpc
echo ' </Limit>' >> $ftpc
echo ' <Limit RETR DELE>' >> $ftpc
echo ' DenyAll' >> $ftpc
echo ' </Limit>' >> $ftpc
echo '</Directory>' >> $ftpc
echo " " >> $ftpc
echo " "
done < list
Thanks in advance.
change from
if [ $rr=="y" ]; then
to
if [ $rr == "y" ]; then
As pointed out in the comments, some command in your loop is reading from standard input. You can either figure out which command that is, and redirect its standard input from /dev/null:
bad_command < /dev/null
or simply use a different file descriptor for the while loop:
while read user rr <&3; do
...
done 3< list
Now the read command is not reading from standard input, but from file descriptor 3, which is unlikely to be in use by any command in the body of the loop.
As pointed out by BMW, you need to fix your if statement:
if [ "$rr" = "y" ]; then
The spaces around the equal sign are necessary, as [ is a command, not part of the if syntax, and it requires 3 distinct arguments ($rr, =, and "y"); it will not parse the single string $rr="y" as a comparison. = is preferred with the [ command, as generally == is not the POSIX equality comparison operator. However, bash does allow ==, but also provides a superior command which does not require $rr to be quoted as required for safety with [:
if [[ $rr == y ]]; then # == or = will work the same
You can save some typing in the last section of your loop by combining the echo statements into a single compound command and redirecting their combined output once:
{
echo ...
echo ...
echo ...
} > "$ftpc"
Another option as pointed out by tripleee, requires only a single call to cat. It spawns an external process, but looks cleaner.
cat > "$ftpc" <<EOF
#$1
<Directory $uhome/res-devres/>
etc
EOF
You could also just echo and a single string with embedded newlines.
echo "#$1
<Directory $uhome/res-devres/>
etc
" > "$ftpc"