UNIX shell scripting if and grep command setting - bash

To design a shell that accepts an input string which is a state name, and looks for all the universities that are in that state. If found, it displays all the universities as output, otherwise it displays an error message like “xxx was not found in the file”. Here xxx is the input string. (Hint: This can be done by redirecting the search results to a file and then checking whether the file is empty or not). For example, if the input string is “NSW”, the output should be a list of all the universities in NSW. If the input is “AUS”, an error message should be displayed, saying that “AUS was not found in the file”.
Here is my code:
#!/bin/sh
echo "Please enter State of Uni (e.g NSW ; NAME MUST BE UPPER CASE)"
read State
if [ -n $State ]
then
grep "$State" Aus-Uni.txt
else
echo "$State was not found in the file"
fi
exit
There is no false statement popping up even the string that I entered was not found in the file. Somehow the true statement is roughly executed.

Firstly, you've no way to check whether the user input is compliant with your requirement that it should be all upper-case.
You could use [ shell param expansion ] to convert the input to all-uppercase before processing, well, something like :
echo "Please enter State of Uni (e.g NSW)"
read State
State="${State^^}" # Check ${parameter^^pattern} in the link
Change
if [ -n $State ]
to
if [ -n "$State" ]
# You need to double-quote the arguments for n to work
# You can't use single quotes though because variable expansion won't happen inside single quotes

This only checks whether the string is nonempty
[[ -n $State ]]
The grep runs if the check succeeds - but the success of grep is not checked
Try this
if [[ -n $State ]]; then
if ! grep "$State" Aus-Uni.txt; then
echo "$State was not found in the file"
exit 2
fi
else
echo "State is empty"
exit 1
fi

Related

bash script to trigger on and off events from journalctl

I am trying to write a bash script to set a variable "status" to either online or offline.
I use logger "trigger offline" and logger "trigger online" for simplicity.
The offline event triggers ok, and I can see the output correct in journalctl, but when the online event is sent by logger, the variable £status is still offline. If its offine, I want it to restart the NetworkManger until the event online is triggered. thanks
!/bin/bash
journalctl -fqn0 | \
while read line
do
#trigger if offline
echo "$line" | grep "trigger offline"
if [ $? = 0 ]
then
status="offline"
fi
#trigger if online
echo "$line" | grep "trigger online"
if [ $? = 0 ]
then
status="online"
fi
sleep 3
logger "Status is $status"
if [[ $status="offline" ]]
then
#restart the network here
logger "do some stuff"
fi
done
if [[ $status="offline" ]]
when $status is online means
if [[ online=offline ]]
online=offline is a single string.
[[ string ]] is true if string is non zero. Which is the case.
You wanted to use the string comparison, to call [[ with 3 arguments (not counting the closing ]]), a string, a = and another string, not just one.
In other words
if [[ $status = "offline" ]]
with the correct spaces.
Another thing unrelated to your error, but related to the next one:
I surmise that all line won't contain either 'online' or 'offline'.
So, $status maybe empty (at least at the beginning. Then, it will be whatever it already was for all lines not related to your status. Which may be a 3rd error, but that an applicative problem I can not judge whether this is a problem or not. I do have the feeling that you don't want to log a status line each time a totally unrelated event is shown by journalctl tho. So you may want to reset status to "" at each loop. Not sure. Your call).
But the important point is, whatever you choose, $status maybe the empty string. In which case, your if will become if [[ =offline ]] which is true, and mine if [[ = offline ]] which is a syntax error.
To avoid that, you want to enclose $status in double quotes
So :
if [[ "$status" = "offline ]]

Getting piped data to functions

Example output
Say I have a function, a:
function a() {
read -r VALUE
if [[ -n "$VALUE" ]]; then # empty variable check
echo "$VALUE"
else
echo "Default value"
fi
}
So, to demonstrate piping to that function:
nick#nick-lt:~$ echo "Something" | a
Something
However, piping data to this function should be optional. So, this should also be valid. and give the following output:
nick#nick-lt:~$ a
Default value
However, the function hangs, as the read command waits for data from stdin.
What I've tried
Honestly not a lot, because I don't know much about this, and searching on Google returned very little.
Conceptually, I thought there might be a way to "push" an empty (or whitespace, whatever works) value to the stdin stream, so that even empty stdin at least has this value appended/prepended, triggering read and then simply trim off that first/last character. I didn't find a way to do this.
Question
How can I, if possible, make both of the above scenarios work for function a, so that piping is optional?
EDIT: Apologies, quickly written question. Should work properly now.
One way is to check whether standard input (fd 0) is a terminal. If so, don't read, because that will cause the user to have to enter something.
function a() {
value=""
if [ \! -t 0 ] ; then # read only if fd 0 is a pipe (not a tty)
read -r value
fi
if [ "$value" ] ; then # if nonempty, print it!
echo "$value"
else
echo "Default value"
fi
}
I checked this on cygwin: a prints "Default value" and echo 42 | a prints "42".
Two issues:
Syntactic, You need a space, before closing ]]
Algorithmic, You need the -n (non-zero length) variable test, not -z (zero length)
So:
if [[ -n "$VALUE" ]]; then
Or simply:
if [[ "$VALUE" ]]; then
As [[ is a shell builtin, you don't strictly need the double quotes:
if [[ $VALUE ]]; then
Also refrain from using all uppercases as variable name, as these are usually used for denoting environment variables, and your defined one might somehow overwrite already existing one. So use lowercase variable name:
if [[ $value ]]; then
unless you are export-ing your variable, and strictly need it to be uppercased, also make sure it is not overwriting any already existing one.
Also, i would add a timeout to read e.g. -t 5 for 5 seconds, and if no input is entered, print the default value. Also change the function name to something more meaningful.
Do:
function myfunc () {
read -rt5 value
if [[ "$value" ]]; then
echo "$value"
else
echo "Default value"
fi
}
Example:
$ function myfunc () { read -rt5 value; if [[ "$value" ]]; then echo "$value"; else echo "Default value"; fi ;}
$ myfunc
Default value
$ echo "something" | myfunc
something
$ myfunc
foobar
foobar

How to remove contact from shell script?

I am creating a simple phonebook using unix shell scripts. I have gotten all of my functions to work except the removal of a contact after it has been created. I have tried combining grep and sed in order to accomplish this, but cannot seem to get over the hump. The removal shell i've tried is as follows.
#!/bin/sh
#removeContact.sh
echo “Remove Submenu”
echo “Please input First Name:”
read nameFirst
echo “Please input Last Name:”
read nameLast
x=$(grep -e “$nameFirst” -e “$nameLast” ContactList)
echo $x
sed '/'$x'/ d' ContactList;
echo “$nameFirst $nameLast is removed from your contacts”
exit 0
I'm not sure if I am declaring x incorrectly, or if my syntax is wrong when sed is used.
Any help would be greatly appreciated. Thank you.
#!/bin/bash
ContactList="contacts.txt"
export ContactList
exit=0
while [ $exit -ne 1 ]
do
echo "Main Menu"
echo "(a) Add a Contact"
echo "(r) Remove a Contact"
echo "(s) Search a Contact"
echo "(d) Display All Contact’s Information"
echo "(e) Exit"
echo "Your Choice?"
read choice
if [ "$choice" = "a" ]
then
./addContact.sh
elif [ "$choice" = "r" ]
then
./removeContact.sh
elif [ "$choice" = "s" ]
then
./searchContact.sh
elif [ "$choice" = "d" ]
then
./displayContact.sh
elif [ "$choice" = "e" ]
then
exit=1
else
echo "Error"
sleep 2
fi
done
exit 0
#!/bin/sh
#addContact.sh
ContactList="contacts.txt"
echo “Please input First Name:”
read nameFirst
echo “Please input Last Name:”
read nameLast
echo “Please input Phone Number:”
read number
echo “Please Input Address”
read address
echo “Please input Email:”
read email
echo $nameFirst:$nameLast:$number:$address:$email>> ContactList;
echo "A new contact is added to your book."
exit 0
sed '/'$x'/ d' ContactList
won't remove anything from the file ContactList, it will simply output the changes to standard output.
If you want to edit the file in-place, you'll need the -i flag (easy) or to make a temporary file which is then copied back over ContactList (not so easy, but needed if your sed has no in-place editing option).
In addition, since ContactList is a shell variable referencing the real file contacts.txt, you'll need to use $ContactList.
And, as a final note, since you're using the full line content to do deletion, the presence of an address like 1/15 Station St is going to royally screw up your sed command by virtue of the fact it contains the / character.
I would suggest using awk rather than sed for this task since it's much better suited to field-based data. With the record layout:
$nameFirst:$nameLast:$number:$address:$email
you could remove an entry with something like (including my patented paranoid perfect protection policy):
cp contacts.txt contacts.txt.$(date +%Y.%m.%d.%H.%M.%S_$$)
awk <contacts.txt >tmp.$$ -F: "-vF=$nameFirst" "-vL=$nameLast" '
F != $1 || L != $2 {print}'
mv tmp.$$ contacts.txt

What does the operator != mean in a shell script?

In this i have an exclamation mark in my second if statement why is this used.
#!/bin/bash
name=$1
if [ "$name" = "" ]
then echo -n "Enter a name to search for: "
read name
fi
grep -i cheryl ~uli101/uli101/phonebook
grep -i $name ~uli101/uli101/phonebook
if [ "$?" != "0" ]
then echo -n "Name '$name' not in directory "
fi
The special shell parameter $? contains the exit code from the last command run. Every command you run from the shell reports a numeric status back to the shell when it finishes running; in general, a value of 0 means the command succeeded, and a nonzero value means it failed.
The grep command searches a file for lines matching a pattern. If it finds any matching lines, it prints them out, but it also exits with status 0 if it found at least one match, and a nonzero status if it didn't find any.
The syntax [ expression ] is a command that evaluates the given expression (usually a comparison of some sort) to see if it's true or not. Really, it's just another shell command, that exits with status 0 if the expression is true and 1 if it's false; the if construct in the shell decides what to do based on the value of $?.
And the != operator means 'is not equal to', so [ $? != 0 ] is checking to see if $? is not equal to zero.
Putting all that together, the above code checks to see if the grep found a match or not.
The origin of != is the C family of programming languages, in which the exclamation point generally means "not". In bash, a ! at the start of a command will invert the exit status of the command, turning nonzero values to zero and zeroes to one. So you could also "move the exclamation point" and rewrite the above expression like this:
if ! [ $? == 0 ]
However, since if itself operates based on exit status, all of the above code is doing extra work. You can skip the middleman and just test grep directly:
if ! grep -i "$name" ~uli101/uli101/phonebook; then
echo "Name '$name' not in directory."
fi
Note that I put double quotes around $name, which prevents any spaces in the value from separating it into multiple arguments to grep.
[ "$?" != "0" ] means "$? not equal to 0". See the full list of Bash test operators here.
Note that $? will be set to 0 if grep finds a match, and 1 otherwise.

How do I use a file grep comparison inside a bash if/else statement?

When our server comes up we need to check a file to see how the server is configured.
We want to search for the following string inside our /etc/aws/hosts.conf file:
MYSQL_ROLE=master
Then, we want to test whether that string exists and use an if/else statement to run one of two options depending on whether the string exists or not.
What is the BASH syntax for the if statement?
if [ ????? ]; then
#do one thing
else
#do another thing
fi
From grep --help, but also see man grep:
Exit status is 0 if any line was selected, 1 otherwise;
if any error occurs and -q was not given, the exit status is 2.
if grep --quiet MYSQL_ROLE=master /etc/aws/hosts.conf; then
echo exists
else
echo not found
fi
You may want to use a more specific regex, such as ^MYSQL_ROLE=master$, to avoid that string in comments, names that merely start with "master", etc.
This works because the if takes a command and runs it, and uses the return value of that command to decide how to proceed, with zero meaning true and non-zero meaning false—the same as how other return codes are interpreted by the shell, and the opposite of a language like C.
if takes a command and checks its return value. [ is just a command.
if grep -q ...
then
....
else
....
fi
Note that, for PIPE being any command or sequence of commands, then:
if PIPE ; then
# do one thing if PIPE returned with zero status ($?=0)
else
# do another thing if PIPE returned with non-zero status ($?!=0), e.g. error
fi
For the record, [ expr ] is a shell builtin† shorthand for test expr.
Since grep returns with status 0 in case of a match, and non-zero status in case of no matches, you can use:
if grep -lq '^MYSQL_ROLE=master' ; then
# do one thing
else
# do another thing
fi
Note the use of -l which only cares about the file having at least one match (so that grep returns as soon as it finds one match, without needlessly continuing to parse the input file.)
†on some platforms [ expr ] is not a builtin, but an actual executable /bin/[ (whose last argument will be ]), which is why [ expr ] should contain blanks around the square brackets, and why it must be followed by one of the command list separators (;, &&, ||, |, &, newline)
just use bash
while read -r line
do
case "$line" in
*MYSQL_ROLE=master*)
echo "do your stuff";;
*) echo "doesn't exist";;
esac
done <"/etc/aws/hosts.conf"
Below code sample should work:
(echo "hello there" | grep -q "AAA") && [ $? -eq 0 ] && echo "hi" || echo "bye"

Resources