Select and Case statements using BASH - bash

The idea behind this code is to print options to the user and allow them to execute commands. The file name is example.sh. I simply run it by ./example.sh and it gives 3 options: author, type, exit.
NAME="Mark Zuck"
PS3="enter command: "
select var in author type exit
do
case $var in
author)
echo $NAME
;;
type)
cat $2
;;
exit)
exit
;;
esac
done
Whenever I type author, the output is Mark Zuck, but I am trying to execute the command "type".
After putting 2 <"file name">, it should give me the contents of the file.
cat $2 doesn't work. I don't know how to solve this issue.
1) author
2) type
3) exit
enter command: 2 file1
enter command:
The output is above.
It should give me the content of the "file1" (file1 does exist)

select returns two values:
The first is in your custom var and contains the token associated to the number in select list
The second is in REPLY (like built-in read command) and contains the number
Ok? it's the standard test case.
If you type another response on select prompt, var is nul (empty) and REPLY contains the response!
So, I think, this script is for you.
Of course, the coma (,) is not adapted for you, it's just an example. Use what you want.
#! /usr/bin/env bash
NAME="Mark Zuck"
PS3="enter command: "
select var in author type exit
do
case "$var,$REPLY" in
"author,1")
echo "$NAME"
;;
",2 "*)
filename="${REPLY#2 }"
echo "filename=<$filename>"
cat "${filename}"
;;
"exit,3")
exit
;;
esac
done
Test:
> bash --version
GNU bash, version 5.2.9(1)-release (x86_64-redhat-linux-gnu)
> ./test_select.sh
1) author
2) type
3) exit
enter command: 1
Mark Zuck
enter command: 2 test_select.sh
filename=<test_select.sh>
#! /usr/bin/env bash
NAME="Mark Zuck"
PS3="enter command: "
select var in author type exit
do
case "$var,$REPLY" in
"author,1")
echo "$NAME"
;;
",2 "*)
filename="${REPLY#2 }"
echo "filename=<$filename>"
cat "${filename}"
;;
"exit,3")
exit
;;
esac
done
enter command: 3
>

Related

showing instructions for command line inputs in a bash script when run without inputs or wrong inputs

I have created a bash script which takes 2 command line arguments. It works absolutely fine.
I want to go a step further, and want to show the types of arguments it takes. i.e. if we run my_script.bash --help it should tell the desired arguments in its order.
my_script.bash is as follows
#!/bin/bash
X="$1" ## Name
Y="$2" ## address
echo " Mr./Ms. $X lives in $Y ."
Since it takes two arguments name and address, I want to show these when this bash is executed without any inputs or number of inputs or using my_script.bash --help command.
ie executing ./my_script.bash or ./my_script.bash --help should show like below
$ ./my_script.bash
>>this script takes two arguments. please enter **Name** and **address**
Since these arguments are position specific so we cannot change the positions of Name and Address. It would be great if we could pass the arguments by defining --name --address.
$ ./my_script.bash --address Delhi --name Gupta
>> Mr./Ms. Gupta lives in Delhi .
Any help would be appreciated.
A basic option parsing loop uses while and case, and looks like this:
print_help ()
{
cat <<-EOF
${0##*/} - process name and address
--name NAME your name
--address ADDRESS your address
--help this help
EOF
}
die ()
{
echo "$#" >&2
exit 1
}
while [[ $# -gt 0 ]]; do
case $1 in
--help)
print_help
exit
;;
--name)
shift || die "$1: requires input"
name=$1
;;
--address)
shift || die "$1: requires input"
address=$1
;;
*)
die "$1: invalid argument"
esac
shift
done
The order of options doesn't matter.
You can test for [[ $1 == --help ]], but since your script has 2 required arguments, you could simply print the help whenever the number of arguments is not equal 2:
if (( $# != 2 ))
then
echo You have to provide 2 arguments 1>&2
exit 1
fi

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

How to make my script menu execute my subscripts in Unix

Sorry in advance since i am new to Unix coding. I have a Bash shell script that generates 2 other subscripts. The main script implements a menu that gives a choice to the user in which script to generate.
I have two problems. The first one is how to make the script that the user selects to execute when he selects it, and the second how to implement input validation in my menu so when the user inputs something different that 1 and 2 to get an error message. This is my code so far:
#!/bin/bash
echo "Welcome to scriptGen."
echo "Please select a script to execute by choosing 1 or 2:"
scripts="bDir mMail"
select option in $scripts
do
echo "You have selected script $option to execute."
done
cat > bDir.sh <<EOF1
#!/bin/bash
#code
EOF1
chmod +x bDir.sh
cat >mMail.sh <<EOF2
#!/bin/bash
#code
EOF2
chmod +x mMail.sh
Thanks for your time!
So you'll probably want a case statement for your user to select their input.
Also, I'm not sure what you're doing with the dynamic writing of scripts, but you'll probably be better off with functions in your code.
Something like the following:
#!/bin/bash
main () {
echo "Welcome to scriptGen."
echo
echo "1: bDir"
echo "2: mMail"
echo -n "Please select a script to execute by choosing 1 or 2: "
read user_input
case $user_input in
1)
bdir
;;
2)
mmail
;;
*)
echo "Unrecognised option '$user_input'. Exiting..."
exit 1
;;
esac
}
bdir () {
echo "Running bDir"
}
mmail () {
echo "Running mmail"
}
main "$#"
Explanation:
main () {
...
}
Creating a function called main. It's a clear enough name to let the user know what function is going to get called first.
echo -n "Please select a script to execute by choosing 1 or 2: "
The -n removes the new-line at the end. This gives a nicer user experience when they're prompted.
read user_input
Read the user's input and store it in the variable user_input. The capture will finish when the user presses enter. However, this can be combined with other flags like -n 1 to capture just 1 character and continue without requiring the user to press enter.
case $user_input in
1)
bdir
;;
2)
mmail
;;
*)
echo "Unrecognised option '$user_input'. Exiting..."
exit 1
;;
esac
A case statement. Given the value of user_input, if it's 1, run the bdir function. If it's 2 run the mmail function. Otherwise, echo the warning and exit.
main "$#"
Run our main function. We use $# to ensure all of the variables passed into the script are also passed into the main function.

bash script with case statement

I have a file called Namebook, with following data inside:
$ cat Namebook
Kamala Hasan 123
Rajini kanth 345
Vijay 567
Ajith kumar 908
$
Then I have a bash script to add a new name in the file Namebook, called add_name.sh
$ cat add_name.sh
#!/bin/bash
echo "$1 $2" >> Namebook
$
Next I have a script to look someone from this Namebook, called look_up.sh
$ cat look_up.sh
#!/bin/bash
grep "$1" Namebook
$
Then again I have a script to remove someone from this Namebook, called remove.sh
$ cat remove.sh
#!/bin/bash
grep -v "$1" Namebook > tmp/Namebook
mv tmp/Namebook Namebook
$
These scripts add, lookup and remove users from the Namebook file.
Based on the combination of these three script, I created a single script, all_action.sh, to perform all said actions
$cat all_action.sh
#!/bin/bash
echo 'Select the option
1. Lookup some one from the Namebook
2. Add name to Namebook
3. Remove name from the Namebook
Select the options range of (1-3): \c '
read choice
case "$choice"
in
1) "Enter the name to lookup: \c"
read name
look_up "$name" ;;
2) "Enter the name to be add: \c"
read name
"Enter the number to be add: \c"
read number
add_name "$name" "$number" ;;
3) "Enter the name to be remove: \c"
read name
remove "$name ;;
esac
My question: when I execute the program all_action.sh, it throws an error
For example: I am going to run ./all_action.sh
Select the option
1. Lookup some one from the Namebook
2. Add name to Namebook
3. Remove name from the Namebook
Select the options range of (1-3): \c
1
Enter name to be lookup
Kamala Hasa
./all_action.sh: line no : look_up: command not found
Could you please any one help on this ?
The commands: look_up, add_name, remove are not found. Put the complete path in your script and specify the Interpreter:
sh /home/myuser/myscript.sh
or with relative path:
sh ./myscript.sh

How to run my bash functions in terminal using a parent name?

* the wording of the question is terrible, sorry!
I have some bash functions I create
test() {echo "hello wold"}
test2() {echo "hello wold"}
Then in my .bashrc I source the file that has the above function . ~/my_bash_scripts/testFile
In the terminal I can run test and get hello world.
is there a way for me to add parent variable that holds all my functions together. For example personal test, personal test2.
Similar to every other gem out there, I downloaded a tweeter one. All it's methods are followed by the letter t, as in t status to write a status, instead of just status
You are asking about writing a command-line program. Just a simple one here:
#!/usr/bin/env bash
if [[ $# -eq 0 ]]; then
echo "no command specified"
exit
elif [[ $# -gt 1 ]]; then
echo "only one argument expected"
exit
fi
case "$1" in
test)
echo "hello, this is test1"
;;
test2)
echo "hello, this is test2"
;;
*)
echo "unknown command: $1"
;;
esac
Then save it and make it an executable by run chmod +x script.sh, and in your .bashrc file, add alias personal="/fullpath/to/the/script.sh".
This is just very basic and simple example using bash and of course you can use any language you like, e.g. Python, Ruby, Node e.t.c.
Use arguments to determine final outputs.
You can use "$#" for number of arguments.
For example,
if [ $# -ne 2 ]; then
# TODO: print usage
exit 1
fi
Above code exits if arguments not euqal to 2.
So below bash program
echo $#
with
thatscript foo bar baz quux
will output 4.
Finally you can combine words to determine what to put stdout.
If you want to flag some functions as your personal functions; no, there is no explicit way to do that, and essentially, all shell functions belong to yourself (although some may be defined by your distro maintainer or system administrator as system-wide defaults).
What you could do is collect the output from declare -F at the very top of your personal shell startup file; any function not in that list is your personal function.
SYSFNS=$(declare -F | awk '{ a[++i] = $3 }
END { for (n=1; n<=i; n++) printf "%s%s", (n>1? ":" : ""), a[n] }')
This generates a variable SYSFNS which contains a colon-separated list of system-declared functions.
With that defined, you can check out which functions are yours:
myfns () {
local fun
declare -F |
while read -r _ _ fun; do
case :$SYSFNS: in *:"$fun":*) continue;; esac
echo "$fun"
done
}

Resources