BASH SELECT CASE using list from a file as variables - bash

name01=$(echo "Data 01")
name02=$(echo "Data 02")
echo "Please select data : "
PS3="Answer : "
optionname=(
"$name01"
"$name02"
"$name99")
select opt1 in "${optionname[#]}"
do
case $opt1 in
$name01) echo "$name01" ; break ;;
$name02) echo "$name02" ; break ;;
$name99) echo "Please enter the data : " ; read "name99" ; break ;;
*) echo invalid option;;
esac
done
This is part of my current script, and only have 12 data for now, but the amount and name of the data will change over time, so I need the data/variable (name01, name02, name03, ...) imported from a list from a separate text file. Let say the file look like this inside :
aa bb
aaaa ccc
ab cdd
Need advice,
Thanks in advance

If you just want to validate user input against a list of options in a file, then you could simply use grep:
Given a list of options in options.txt.
banana
apple
pear
And a script (option.bash):
#!/bin/bash
read -p 'Please enter your favourite fruit: ' fruit_input
if grep -q -o -x -- "$fruit_input" options.txt; then
echo "Your favourite fruit is: $fruit_input"
else
echo "The only fruits you're allowed to choose are:"
cat options.txt
fi
You can use grep to validate that the user entered an allowed option:
./option.bash
Please enter your favourite fruit: apple
Your favourite fruit is: apple
./option.bash
Please enter your favourite fruit: cheese
The only fruits you're allowed to choose are:
banana
apple
pear

Here is the update for my script, list is on /tmp/name_list
touch /tmp/number_list
touch /tmp/number_name_list
amount=$(cat /tmp/name_list | wc -l)
a=0
while [[ $a -lt $amount ]]; do
let a=$a+1
echo $a >> /tmp/number_list
name=$(sed -n "${a}p" /tmp/name_list)
echo "$a $name">> /tmp/number_name_list
done
cat /tmp/number_name_list
read -p "Please enter the number or enter new name : " input
if
grep -q -o -x -- "$input" /tmp/number_list
then
folder=$(sed -n "${input}p" /tmp/name_list)
echo "its $folder"
mkdir /tmp/"$folder"
else
echo "its $input"
mkdir /tmp/"$input"
fi
Thank you to #Robert Seaman for reminding me to use if then else instead of case

Related

why is a bash read prompt not appearing when a script is run?

I have a bash script that prompts the user for different information based on what they're trying to do. The prompts are usually done with read -p. Usually it works just fine, the user sees what is being asked, enters what they need to enter, and everything does what it needs to do.
See the following (sanitized) snippet of a function in the script:
#!/bin/bash
function_name() {
if [ "$this_value" == "default" ];then
echo "Value set to default."
read -p "Enter desired value here: " desired_value
desired_value=${desired_value^^}
if [ "${#desired_value}" != 3 ] ;then
echo "$desired_value is an invalid entry."
exit 1
fi
if [ "$desired_value" != "$(some command that returns something to compare against)" ];then
echo "$desired_value is an invalid entry."
exit 1
fi
read -p "You entered $desired_value. Is this correct? [y/N] " reply
reply=${reply,,}
case "$reply" in
y|yes)
$some command that does what I want it to do
;;
*)
echo "User did not enter yes"
exit 1
;;
esac
fi
}
Usually the Enter desired value here and is this correct? lines appear just fine. But in a few instances I've seen, for some reason the read prompt is just blank. A user will see the following:
./script.bash
##unrelated script stuff
##unrelated script stuff
Value set to default.
user_entered_value_here
User did not enter yes. Exiting.
This is a real example that just happened that finally made me come here to ask what is going on (and I modified appropriately to make it an SO post).
What's happening is these two blank lines appear instead of the read -p text. For the first one, the user entered user_entered_value_here because they already know what is supposed to be entered there even without the read prompt. The second one, the Y/N prompt, they don't know, so they see it apparently hanging, and hit Enter instead of y, causing it to trigger the * case option.
I don't understand why the read -p text is not appearing, and especially why it's appearing for most users but not all users. I suspect there's some kind of environmental setting that causes this, but for the life of me I can't figure out what. This is being run only on RHEL 6.2, under bash 4.1.2.
I looked at the man of bash to catch some kind of detail about the read built-in. It is specified that -p option displays the "prompt on standard error, without a trailing newline, before attempting to read any input. The prompt is displayed only if input is coming from a terminal".
Let's consider the simple script input.sh:
#!/bin/bash
read -p "Prompt : " value
echo The user entered: "$value"
Example of execution:
$ ./input.sh
Prompt : foo
The user entered: foo
If stderr is redirected:
$ ./input.sh 2>/dev/null
foo
The user entered: foo
If the input is a pipe
$ echo foo | ./input.sh
The user entered: foo
If the input is a heredoc
$ ./input.sh <<EOF
> foo
> EOF
The user entered: foo
Rewrote your script with shell agnostic grammar and fixed some errors like comparing the string length with a string comparator != = rather than a numerical comparator -ne -eq:
#!/usr/bin/env sh
this_value=default
toupper() {
echo "$1" | tr '[:lower:]' '[:upper:]'
}
function_name() {
if [ "$this_value" = "default" ]; then
echo "Value set to default."
printf "Enter desired value here: "
read -r desired_value
desired_value=$(toupper "$desired_value")
if [ "${#desired_value}" -ne 3 ]; then
printf '%s is an invalid entry.\n' "$desired_value"
exit 1
fi
if [ "$desired_value" != "$(
echo ABC
: some command that returns something to compare against
)" ]; then
echo "$desired_value is an invalid entry."
exit 1
fi
printf 'You entered %s. Is this correct? [y/N] ' "$desired_value"
read -r reply
reply=$(toupper "$reply")
case $reply in
'y' | 'yes')
: "Some command that does what I want it to do"
;;
*)
echo "User did not enter yes"
exit 1
;;
esac
fi
}
function_name

Bash: While loop error

I'm trying to write a program where the program will ask you your name, confirm that you want this name, then check to see if you said yes or no. I have the "no" loop working, where it will ask for a name again, but I'm trying to a loop where if you type anything other than yes or no it will say "Please type yes or no." then ask if you want to confirm your name, then check the answer again. Heres what I have.
echo -e $WHITE"Name your$GREEN Hero$WHITE."
read HERO
clear
echo -e "Are you sure you want your$GREEN Hero$WHITE's name to be$GREEN "$HERO"$WHITE? y/n"
read ANSWER1
while [ $ANSWER1 = "no" ]; do
#
#
#
clear
echo -e $WHITE"Name your$GREEN Hero$WHITE."
read HERO
clear
echo -e "Are you sure you want your$GREEN Hero$WHITE's name to be$GREEN "$HERO"$WHITE? y/n"
read ANSWER1
done
while [ $ANSWER1 != "yes" ] || [ $ANSWER1 != "no" ]; do
#
#
#
clear
echo -e $WHITE"Please type yes or no."
sleep 1.5
clear
echo -e $WHITE"Are you sure you want your$GREEN Hero$WHITE's name to be$GREEN "$HERO"$WHITE?"
read ANSWER1
clear
done
clear
echo -e -n $WHITE"Loading"
sleep 1.5
echo -e -n "."
sleep 1.5
echo -e -n "."
sleep 1.5
echo -e -n "."
sleep 1.5
clear
echo -e "Done."
If I go through the "Please type yes or no." it will freeze at the sleep and not clear, therefore not displaying the echo and continuing the loop. Any help or suggestions would be greatly appreciated!
Here's the problem:
while [ $ANSWER1 != "yes" ] || [ $ANSWER1 != "no" ]; do
Every possible answer is different to at least one of them. There's no string that's equal to yes and no at the same time. You need && instead of ||.
An easier way to write a loop to get user's input is the select command:
while true; do
read -p "${white}Name your ${green}Hero$white: " hero
echo "Are you sure you want your ${green}Hero$white's name to be $green\"$hero\"$white? "
select ans in Yes No; do
case $ans in
Yes) break 2 ;; # break out of both select and while loops
No) break ;; # only break out of select loop
esac
done
done
echo "Your ${green}Hero$white's name is $green\"$hero\"$white."

define "$key" use it in a script, but also store it

How can I create a specific line in another file using bash please? Like
echo "Please input the days you want to keep "
$key= ?
touch .beebrc; keep="$key"
where the file ".beebrc" has a line 'keep= x' and "$key" is created in the main script.
But how do I define "$key" please? And write it into ".beebrc" as a new line at position/line 8? The full function is -
function trim {
echo;
read -t "$temi" -n1 -p ""$bldgrn" Do you want to delete some of your download history? [y/n/q/r] $(tput sgr0)" ynqr ;
case "$ynqr" in
[Yy]) echo
read -t "$temi" -n3 -p ""$bldgrn" Please input the days you want to keep $(tput sgr0)" key ## ask
if test -e .beebrc && grep -q "^keep=" .beebrc 2>/dev/null ; then
sed -i "s/^keep=.*/keep=$key/" .beebrc
else
echo "keep=$key" >> .beebrc
#fi
cd /home/$USER/.get_iplayer
eval "$player" --trim-history "$key"; cd; ques;
#echo;;
[Nn]) ques;;
[Qq]) endex;;
[Rr]) exec "$beeb";;
* ) echo ""$bldgrn" Thank you $(tput sgr0)";;
esac
fi
};
Does this help in defining it all? (Sorry, should've put it in at first)
Perhaps:
read -p "Please input the days you want to keep: " key ## Ask.
echo "keep=\"$key\"" > .beebrc ## Store.
Use read to capture user input into a variable, and then write it to your file.
For example:
echo "Please input the days you want to keep "
read key
echo $key > .beebrc
#!/bin/bash
read -p "Please input the days you want to keep: " key
if test -e .beebrc && grep -q "^keep=" .beebrc 2>/dev/null ; then
sed -i "s/^keep=.*/keep=$key/" .beebrc
else
echo "keep=$key" >> .beebrc
fi
This script:
Prompts for input and stores the value in $key
Tests if .beebrc exists and that a line beginning "keep=" exists in it. If so, replace the keep= line with keep=$key
Otherwise append a new line/create the file with keep=$key.
This will need validation added because user input should not be trusted. (this answer might help)

Shell scripting - Email script based on user input

I want to create a email script that really is a texting script that is using the mail -x and sending to numbers. It would go something like this:
#/bin/sh
Joe=8881235555
Bob=8881235556
echo "Who do you want to text?:(i.e. Joe, Bob, etc)"
read name
echo "What do you want to say?:)"
read quote
echo "texting $name with $quote"
echo $variablequote | mailx -s "Text Message via email" $variablename#txt.att.net
How do I get that user input name to transfer in to a preset value?
Consider using a more modern shell:
#!/bin/bash
# Use an associative array, and map names to numbers
declare -A numbers
numbers=([Joe]=8881235555 [Bob]=8881235556)
echo "Who do you want to text?:(i.e. Joe, Bob, etc)"
read name
echo "What do you want to say?:)"
read quote
# Look up number by name
number=${numbers[$name]}
if [[ $number ]]
then
echo "texting $name ($number) with $quote"
mailx -s "Text Message via email" "$number#txt.att.net" <<< "$quote"
else
echo "Unknown user"
exit 1
fi
If you want to use /bin/sh:
#!/bin/sh
# Prefix the numbers with something
number_Joe=8881235555
number_Bob=8881235556
echo "Who do you want to text?:(i.e. Joe, Bob, etc)"
read name
echo "What do you want to say?:)"
read quote
# Remove any dangerous characters that the user enters
sanitized=$(printf "%s" "$name" | tr -cd 'a-zA-Z')
# Look up by evaluating e.g. "number=$number_Joe"
eval "number=\$number_$sanitized"
if [ "$number" ]
then
echo "texting $name ($number) with $quote"
printf "%s\n" "$quote" | mailx -s "Text Message via email" "$number#txt.att.net"
else
echo "Unknown user"
exit 1
fi

Whats the Vi command to delete a line from a file from a user input?

I have a file and want to delete lines when user enters an ID in UNIX/Vi.
The file is called 'users' and contains:
001:joe:one:20:01:02
002:joe:two:21:06:02
003:joe:three:22:05:02
004:joe:four:23:04:02
I have used the following function in Vi:
function deleteRecord()
{
echo "Please enter staff ID: "
read userID
#store staffID in variable
sID=$( grep -w "$userID" users )
#store staff details only if user does not exist
#else prompt them to input again until they enter unused data
if [ $? -ne 0 ]
then
echo "Sorry that user does not exist!"
echo "Try entering a different staff ID to delete"
deleteRecord
elif [ $? -eq 0 ]
then
#:g/^$userID:/d
#sed /$userID/d users >tmp
#imv tmp users
echo "You have successfully deleted the user."
sleep 2
mainMenu
fi
}
I have tried that but it does not work! Is sed the problem?
Please help.
You're best off using the built in functionality. e.g.
:g/^theuserid:/d
Only for fun - here is your homework. Next time tag it.
#!/bin/bash
IDFILE="./testfile"
function killVogon() {
while read -p 'Enter Vogon-ID (or "q" for return) >' id
do
case "$id" in
(q|Q) return;;
esac
grep "^0*$id:" "$IDFILE" >/dev/null 2>&1
case $? in
(0) ;;
(1) echo "Although it is infinitely improbable, the '$id' does not exists!"; continue;;
(*) echo "You're blind and can't see any Vogons around"; sleep 1 ; return;;
esac
sed -i '.bak' -e "/^0*$id:/d" "$IDFILE"
case $? in
(0) echo "The Vogon is successfully killed"; sleep 1; return;;
(*) echo "Huh... Marvin, powered with pangalactic gargleblaster is too paranoid now. The Vogon is NOT killed" ;;
esac
done
}
killVogon

Resources