Searching a string in shell script - linux

I am trying to learn shell script. So sorry if my question is so simple.
I am having a file called one.txt and if either strings 1.2 or 1.3 is present in the string then I have to display the success message else the failure message.
The code I tried is follows,
#!/bin/bash
echo "checking"
if grep -q 1.2 /root/one | grep -q 1.3 /root/one; then
echo " vetri Your NAC version"
fi
What I am doing wrong here ?

You can also include the OR in your grep pattern like so:
grep '1.2\|1.3' /root/one
details here
Update:
as twalberg pointed out in the comment, my answer was not precise enough. The better pattern is:
grep '1\.2\|1\.3' /root/one
Or even better, because more compact:
grep '1\.[23]' /root/one

You have to use ||
#!/bin/bash
echo "checking"
if grep -q 1.2 /root/one || grep -q 1.3 /root/one; then
echo " vetri Your NAC version"
fi
Single | operator is called pipe. It will pass the output of the command before | to the command after |.

It is better to join these these greps with | (OR operator):
grep '1.2\|1.3'
or
grep -E '1.2|1.3'

I guess the easier way to do this is to create a variable to check the count of occurrences:
#!/bin/bash
echo "checking"
CHECK=`egrep -c '1\.(2|3)' /root/one`
if [ "$CHECK" -gt 0 ]; then
echo "vetri Your NAC version"
fi

Related

Using grep in an if statement

My goal is to write a shell script take the users that I have already filtered out of a file and check whether those users have a certain string, and if they do, label them as major, if not, nonmajor. My trouble is coming from my first if statement, and I'm not sure if grep is the right way to go in an if statement. Here is what I have:
(
while read i
do
username=`echo $i | grep -v 'CMPSC 1513' | grep -P -v '(?!.*CPSMA 2923)CPSMA' | cut -d'|' -f2`
fullname=`echo $i | grep -v 'CMPSC 1513' | grep -P -v '(?!.*CPSMA 2923)CPSMA' | cut -d'|' -f3`
id=`echo $i | grep -v 'CMPSC 1513' | grep -P -v '(?!.*CPSMA 2923)CPSMA' | cut -d'|' -f4`
if [ $username ]
then
if grep -q "|0510"
then
echo $username":(password):(UID):(GID):"$fullname"+"$id":/home/STUDENTS/majors:/bin/bash"
else
echo $username":(password):(UID):(GID):"$fullname"+"$id":/home/STUDENTS/nonmajors:/bin/bash"
fi
fi
done
)<./cs_roster.txt
Just some info, this is contained in a while loop. In the while loop, i determine whether the person listed should even be major or nonmajor, and my if [ $username ] has been tested and does return all the correct users. At this point the while loop is only running once and then stopping.
Just remove the square brackets and pass $i to grep:
if echo $i | grep -q "|0510"
In your code sample, grep does not have anything to work on.
The "binary operator expected" occurs because you are invoking the command [ with the arguments "grep" and "-q" (you are not invoking grep at all), and [ expects a binary operator where you have specified -q. [ is a command, treated no differently that grep or ls or cat. It is better (IMO) to spell it test, and when invoked by the name test it does not require that its last argument be ]. If you want to use grep in an if statement, just do something like:
if echo "$username" | grep -q "|0510"; then ...
(Although I suspect, depending on the context, there are better ways to accomplish your goal.)
The basic syntax of an if statement is if pipeline; then.... In the common case, the pipeline is the simple command test, and at some point in pre-history, the decision was made to provide the name [ for the test command with the added caveat that its final argument must be ]. I believe this was done in an effort to make if statements look more natural, as if the [ is an operator in the language. Just ignore [ and always use test and much confusion will be avoided.
You can use this code as an exercise. Write an awk script for it, or start with something like
while IFS='|' read -r f1 username fullname id otherfields; do
# I don't know which field you want to test. I will rest with id
if [[ $id =~ ^0510 ]]; then
subdir=majors
else
subdir=nonmajors
fi
echo "${username}:(password):(UID):(GID):${fullname}+${id}:/home/STUDENTS/${subdir}:/bin/bash"
done < <( grep -v 'CMPSC 1513' ./cs_roster.txt | grep -P -v '(?!.*CPSMA 2923)CPSMA' )
This is nice for learning some bash syntax, but consider an awk script for avoiding a while-loop.

Bash: if statement always succeeding

I have the following if statement to check if a service, newrelic-daemon in this case, is running...
if [ $(ps -ef | grep -v grep | grep newrelic-daemon | wc -l) > 0 ]; then
echo "New Relic is already running."
The problem is it's always returning as true, i.e. "New Relic is already running". Even though when I run the if condition separately...
ps -ef | grep -v grep | grep newrelic-daemon | wc -l
... it returns 0. I expect it to do nothing here as the value returned is =0 but my IF condition says >0.
Am I overlooking something here?
You are trying to do a numeric comparison in [...] with >. That doesn't work; to compare values as numbers, use -gt instead:
if [ "$(ps -ef | grep -v grep | grep -c newrelic-daemon)" -gt 0 ]; then
The quotation marks around the command expansion prevent a syntax error if something goes horribly wrong (e.g. $PATH set wrong and the shell can't find grep). Since you tagged this bash specifically, you could also just use [[...]] instead of [...] and do without the quotes.
As another Bash-specific option, you could use ((...)) instead of either form of square brackets. This version is more likely to generate a syntax error if anything goes wrong (as the arithmetic expression syntax really wants all arguments to be numbers), but it lets you use the more natural comparison operators:
if (( "$(ps -ef | grep -v grep | grep -c newrelic-daemon)" > 0 )); then
In both cases I used grep -c instead of grep | wc -l; that way I avoided an extra process and a bunch of interprocess I/O just so wc can count lines that grep is already enumerating.
But since you're just checking to see if there are any matches at all, you don't need to do either of those; the last grep will exit with a true status if it finds anything and false if it doesn't, so you can just do this:
if ps -ef | grep -v grep | grep -q newrelic-daemon; then
(The -q keeps grep from actually printing out the matching lines.)
Also, if the process name you're looking for is a literal string instead of a variable, my favorite trick for this task is to modify that string like this, instead of piping through an extra grep -v grep:
if ps -ef | grep -q 'newrelic[-]daemon'; then
You can pick any character to put the square brackets around; the point is to create a regular expression pattern that matches the target process name but doesn't match the pattern itself, so the grep process doesn't find its own ps line.
Finally, since you tagged this linux, note that most Linux distros ship with a combination ps + grep command called pgrep, which does this for you without your having to build a pipeline:
if pgrep newrelic-daemon >/dev/null; then
(The MacOS/BSD version of pgrep accepts a -q option like grep, which would let you do without the >/dev/null redirect, but the versions I've found on Linux systems don't seem to have that option.)
There's also pidof; I haven't yet encountered a system that had pidof without pgrep, but should you come across one, you can use it the same way:
if pidof newrelic-daemon >/dev/null; then
Other answers have given you more details. I would do what you are trying to do with:
if pidof newrelic-daemon >/dev/null; then
echo "New Relic is already running."
fi
or even
pidof newrelic-daemon >/dev/null && echo "New Relic is already running."
If you want to compare integers with test you have to use the -gt option. See:
man test
or
man [
#Stephen: Try(change [ to [[ into your code along with fi which will complete the if block completely):
if [[ $(ps -ef | grep -v grep | grep newrelic-daemon | wc -l) > 0 ]]; then
echo "New Relic is already running."
fi

Find and highlight text in linux command line

I am looking for a linux command that searches a string in a text file,
and highlights (colors) it on every occurence in the file, WITHOUT omitting text lines (like grep does).
I wrote this handy little script. It could probably be expanded to handle args better
#!/bin/bash
if [ "$1" == "" ]; then
echo "Usage: hl PATTERN [FILE]..."
elif [ "$2" == "" ]; then
grep -E --color "$1|$" /dev/stdin
else
grep -E --color "$1|$" $2
fi
it's useful for stuff like highlighting users running processes:
ps -ef | hl "alice|bob"
Try
tail -f yourfile.log | egrep --color 'DEBUG|'
where DEBUG is the text you want to highlight.
command | grep -iz -e "keyword1" -e "keyword2" (ignore -e switch if just searching for a single word, -i for ignore case, -z for treating as a single file)
Alternatively,while reading files
grep -iz -e "keyword1" -e "keyword2" 'filename'
OR
command | grep -A 99999 -B 99999 -i -e "keyword1" "keyword2" (ignore -e switch if just searching for a single word, -i for ignore case,-A and -B for no of lines before/after the keyword to be displayed)
Alternatively,while reading files
grep -A 99999 -B 99999 -i -e "keyword1" "keyword2" 'filename'
command ack with --passthru switch:
ack --passthru pattern path/to/file
I take it you meant "without omitting text lines" (instead of emitting)...
I know of no such command, but you can use a script such as this (this one is a simple solution that takes the filename (without spaces) as the first argument and the search string (also without spaces) as the second):
#!/usr/bin/env bash
ifs_store=$IFS;
IFS=$'\n';
for line in $(cat $1);
do if [ $(echo $line | grep -c $2) -eq 0 ]; then
echo $line;
else
echo $line | grep --color=always $2;
fi
done
IFS=$ifs_store
save as, for instance colorcat.sh, set permissions appropriately (to be able to execute it) and call it as
colorcat.sh filename searchstring
I had a requirement like this recently and hacked up a small program to do exactly this. Link
Usage: ./highlight test.txt '^foo' 'bar$'
Note that this is very rough, but could be made into a general tool with some polishing.
Using dwdiff, output differences with colors and line numbers.
echo "Hello world # $(date)" > file1.txt
echo "Hello world # $(date)" > file2.txt
dwdiff -c -C 0 -L file1.txt file2.txt

Cut the GREP command in Linux

Okay so i have a variable called search which holds the string "Find this Code - Now". I want to search for that code and if it finds it the system would reply with true or something on those lines, if it doesn't then it just exits the script with error.
I tried to use grep but i couldn't figure out how to cut only what was searched for so i could run an if else statement
You can use the -q switch and check the exit status of grep, i.e. something like grep -q $var <file> && echo "true".
I tried to use grep but i couldn't figure out how to cut only what was searched for so i could run an if else statement
Grep has a switch --only-matching
-o, --only-matching show only the part of a line matching PATTERN
> X="not gonna find it"
> grep -qR "$X" .; echo $?
1
> X="Find this Code - Now"
> grep -qR "$X" .; echo $?
0

Linux Shell Script Illegal number

I am trying to find out the number of occurrences of pattern in a file with following code:
#!/bin/sh
var='grep -c 'abc' file1'
if [ "$var" -lt 10 ]; then
echo "less than 10"
fi
I am getting the error: Illegal number: grep -c abc file1
Can someone please help.
Thanks.
Use backticks (`) instead of apostrophes ('):
#!/bin/sh
var=`grep -c 'abc' file1`
if [ "$var" -lt 10 ]; then
echo "less than 10"
fi
You probably want backticks (`) rather than single-quotes ('). i.e.:
var=`grep -c 'abc' file1`
You've used a single quote rather than a backtick so your var variable is actually set to a string literal rather than the result of that command. You'd see that if you echoed the variable first:
pax$ var='grep -c 'abc' file1'
pax$ echo "[$var]"
[grep -c abc file1]
The backtick version would be:
var=`grep -c 'abc' file1`
But I'd like to suggest using bash where possible for scripting. You'll be hard-pressed finding a mainstream distro that doesn't have it by default and it's considered by some to be more powerful than other shells. In fact, on some systems, /bin/sh is bash.
If you can go that rute, the $() construct is usually a better idea since you can nest them without pain:
var=$(grep -c 'abc' file1)
Try posting the followings to get better answer:
grep --version
bash --version if your shell is Bash or let us know which shell you are using.
use grep within back-ticks or as shown below
[[ is more versatile in Bash than [.
Finally, the following works on my machine without any error:
#!/bin/bash
var=$(grep -c "abc" file1)
if [[ "$var" -lt 10 ]]
then
echo "less than 10"
fi
Execution:
user#machine:~$ cat file1
abc
abcd
abcde
abcdef
user#machine:~$
user#machine:~$ ./t.sh
less than 10
user#machine:~$

Resources