How to test if string exists in file with Bash? - string

I have a file that contains directory names:
my_list.txt :
/tmp
/var/tmp
I'd like to check in Bash before I'll add a directory name if that name already exists in the file.

grep -Fxq "$FILENAME" my_list.txt
The exit status is 0 (true) if the name was found, 1 (false) if not, so:
if grep -Fxq "$FILENAME" my_list.txt
then
# code if found
else
# code if not found
fi
Explanation
Here are the relevant sections of the man page for grep:
grep [options] PATTERN [FILE...]
-F, --fixed-strings
        Interpret PATTERN as a list of fixed strings, separated by newlines, any of which is to be matched.
-x, --line-regexp
        Select only those matches that exactly match the whole line.
-q, --quiet, --silent
        Quiet; do not write anything to standard output. Exit immediately with zero status if any match is found, even if an error was detected. Also see the -s or --no-messages option.
Error handling
As rightfully pointed out in the comments, the above approach silently treats error cases as if the string was found. If you want to handle errors in a different way, you'll have to omit the -q option, and detect errors based on the exit status:
Normally, the exit status is 0 if selected lines are found and 1 otherwise. But the exit status is 2 if an error occurred, unless the -q or --quiet or --silent option is used and a selected line is found. Note, however, that POSIX only mandates, for programs such as grep, cmp, and diff, that the exit status in case of error be greater than 1; it is therefore advisable, for the sake of portability, to use logic that tests for this general condition instead of strict equality with 2.
To suppress the normal output from grep, you can redirect it to /dev/null. Note that standard error remains undirected, so any error messages that grep might print will end up on the console as you'd probably want.
To handle the three cases, we can use a case statement:
case `grep -Fx "$FILENAME" "$LIST" >/dev/null; echo $?` in
0)
# code if found
;;
1)
# code if not found
;;
*)
# code if an error occurred
;;
esac

Regarding the following solution:
grep -Fxq "$FILENAME" my_list.txt
In case you are wondering (as I did) what -Fxq means in plain English:
F: Affects how PATTERN is interpreted (fixed string instead of a regex)
x: Match whole line
q: Shhhhh... minimal printing
From the man file:
-F, --fixed-strings
Interpret PATTERN as a list of fixed strings, separated by newlines, any of which is to be matched.
(-F is specified by POSIX.)
-x, --line-regexp
Select only those matches that exactly match the whole line. (-x is specified by POSIX.)
-q, --quiet, --silent
Quiet; do not write anything to standard output. Exit immediately with zero status if any match is
found, even if an error was detected. Also see the -s or --no-messages option. (-q is specified by
POSIX.)

Three methods in my mind:
1) Short test for a name in a path (I'm not sure this might be your case)
ls -a "path" | grep "name"
2) Short test for a string in a file
grep -R "string" "filepath"
3) Longer bash script using regex:
#!/bin/bash
declare file="content.txt"
declare regex="\s+string\s+"
declare file_content=$( cat "${file}" )
if [[ " $file_content " =~ $regex ]] # please note the space before and after the file content
then
echo "found"
else
echo "not found"
fi
exit
This should be quicker if you have to test multiple string on a file content using a loop for example changing the regex at any cicle.

Easiest and simplest way would be:
isInFile=$(cat file.txt | grep -c "string")
if [ $isInFile -eq 0 ]; then
#string not contained in file
else
#string is in file at least once
fi
grep -c will return the count of how many times the string occurs in the file.

Simpler way:
if grep "$filename" my_list.txt > /dev/null
then
... found
else
... not found
fi
Tip: send to /dev/null if you want command's exit status, but not outputs.

Here's a fast way to search and evaluate a string or partial string:
if grep -R "my-search-string" /my/file.ext
then
# string exists
else
# string not found
fi
You can also test first, if the command returns any results by running only:
grep -R "my-search-string" /my/file.ext

grep -E "(string)" /path/to/file || echo "no match found"
-E option makes grep use regular expressions

If I understood your question correctly, this should do what you need.
you can specifiy the directory you would like to add through $check variable
if the directory is already in the list, the output is "dir already listed"
if the directory is not yet in the list, it is appended to my_list.txt
In one line: check="/tmp/newdirectory"; [[ -n $(grep "^$check\$" my_list.txt) ]] && echo "dir already listed" || echo "$check" >> my_list.txt

The #Thomas's solution didn't work for me for some reason but I had longer string with special characters and whitespaces so I just changed the parameters like this:
if grep -Fxq 'string you want to find' "/path/to/file"; then
echo "Found"
else
echo "Not found"
fi
Hope it helps someone

If you just want to check the existence of one line, you do not need to create a file. E.g.,
if grep -xq "LINE_TO_BE_MATCHED" FILE_TO_LOOK_IN ; then
# code for if it exists
else
# code for if it does not exist
fi

My version using fgrep
FOUND=`fgrep -c "FOUND" $VALIDATION_FILE`
if [ $FOUND -eq 0 ]; then
echo "Not able to find"
else
echo "able to find"
fi

I was looking for a way to do this in the terminal and filter lines in the normal "grep behaviour". Have your strings in a file strings.txt:
string1
string2
...
Then you can build a regular expression like (string1|string2|...) and use it for filtering:
cmd1 | grep -P "($(cat strings.txt | tr '\n' '|' | head -c -1))" | cmd2
Edit: Above only works if you don't use any regex characters, if escaping is required, it could be done like:
cat strings.txt | python3 -c "import re, sys; [sys.stdout.write(re.escape(line[:-1]) + '\n') for line in sys.stdin]" | ...

A grep-less solution, works for me:
MY_LIST=$( cat /path/to/my_list.txt )
if [[ "${MY_LIST}" == *"${NEW_DIRECTORY_NAME}"* ]]; then
echo "It's there!"
else
echo "its not there"
fi
based on:
https://stackoverflow.com/a/229606/3306354

grep -Fxq "String to be found" | ls -a
grep will helps you to check content
ls will list all the Files

Slightly similar to other answers but does not fork cat and entries can contain spaces
contains() {
[[ " ${list[#]} " =~ " ${1} " ]] && echo 'contains' || echo 'does not contain'
}
IFS=$'\r\n' list=($(<my_list.txt))
so, for a my_list.txt like
/tmp
/var/tmp
/Users/usr/dir with spaces
these tests
contains '/tmp'
contains '/bin'
contains '/var/tmp'
contains '/Users/usr/dir with spaces'
contains 'dir with spaces'
return
exists
does not exist
exists
exists
does not exist

if grep -q "$Filename$" my_list.txt
then
echo "exist"
else
echo "not exist"
fi

Related

Bash command check if string match in command output

I have following command output
$ /opt/CrowdStrike/falconctl -g --aid | grep 'aid='
aid="fdwe234wfgrgf34tfsf23rwefwef3".
I want to check if there is any string after aid= (inside ""). If there is any string, command return code should be 0 and if no value return code must be !=0.
Can someone please help to extend this command to get required output?
Idea is to make sure my bash script to fail if aid= doesn't has any value.
You can use regex to check whether one or more characters exist inside the double quotes. And, you can use regex capture group to extract that value:
if [[ $(/opt/CrowdStrike/falconctl -g --aid | grep 'aid=') =~ ^aid=\"(.+)\"$ ]]; then
aid=${BASH_REMATCH[0]}
echo "aid is $aid"
else
echo "aid not found"
fi
Note that the regex I use is .+ which means 1 or more characters, since you require the string to be non-empty. This is in contrast of the usual .* regex which would have be 0 or more characters.
I don't have falconctl on my system so to mimic its output I'll use a couple files:
$ head falcon*out
==> falcon.1.out <==
some stuff
aid="fdwe234wfgrgf34tfsf23rwefwef3".
some more stuff
==> falcon.2.out <==
some stuff
aid=""
some more stuff
One grep idea:
grep -Eq '^aid="[^"]+"' <filename>
Where:
-E - enable extended regex support
-q - run in silent/quiet mode (suppress all output)
the return code can be captured from $?
Taking for a test drive:
for fname in falcon*out
do
printf "\n############# %s\n" "$fname"
cat "$fname" | grep -Eq '^aid="[^"]+"' "$fname"
echo "return code: $?"
done
This generates:
############# falcon.1.out
return code: 0
############# falcon.2.out
return code: 1

LINUX script bash [duplicate]

I want to check if a file contains a specific string or not in bash. I used this script, but it doesn't work:
if [[ 'grep 'SomeString' $File' ]];then
# Some Actions
fi
What's wrong in my code?
if grep -q SomeString "$File"; then
Some Actions # SomeString was found
fi
You don't need [[ ]] here. Just run the command directly. Add -q option when you don't need the string displayed when it was found.
The grep command returns 0 or 1 in the exit code depending on
the result of search. 0 if something was found; 1 otherwise.
$ echo hello | grep hi ; echo $?
1
$ echo hello | grep he ; echo $?
hello
0
$ echo hello | grep -q he ; echo $?
0
You can specify commands as an condition of if. If the command returns 0 in its exitcode that means that the condition is true; otherwise false.
$ if /bin/true; then echo that is true; fi
that is true
$ if /bin/false; then echo that is true; fi
$
As you can see you run here the programs directly. No additional [] or [[]].
In case if you want to check whether file does not contain a specific string, you can do it as follows.
if ! grep -q SomeString "$File"; then
Some Actions # SomeString was not found
fi
In addition to other answers, which told you how to do what you wanted, I try to explain what was wrong (which is what you wanted.
In Bash, if is to be followed with a command. If the exit code of this command is equal to 0, then the then part is executed, else the else part if any is executed.
You can do that with any command as explained in other answers: if /bin/true; then ...; fi
[[ is an internal bash command dedicated to some tests, like file existence, variable comparisons. Similarly [ is an external command (it is located typically in /usr/bin/[) that performs roughly the same tests but needs ] as a final argument, which is why ] must be padded with a space on the left, which is not the case with ]].
Here you needn't [[ nor [.
Another thing is the way you quote things. In bash, there is only one case where pairs of quotes do nest, it is "$(command "argument")". But in 'grep 'SomeString' $File' you have only one word, because 'grep ' is a quoted unit, which is concatenated with SomeString and then again concatenated with ' $File'. The variable $File is not even replaced with its value because of the use of single quotes. The proper way to do that is grep 'SomeString' "$File".
Shortest (correct) version:
grep -q "something" file; [ $? -eq 0 ] && echo "yes" || echo "no"
can be also written as
grep -q "something" file; test $? -eq 0 && echo "yes" || echo "no"
but you dont need to explicitly test it in this case, so the same with:
grep -q "something" file && echo "yes" || echo "no"
##To check for a particular string in a file
cd PATH_TO_YOUR_DIRECTORY #Changing directory to your working directory
File=YOUR_FILENAME
if grep -q STRING_YOU_ARE_CHECKING_FOR "$File"; ##note the space after the string you are searching for
then
echo "Hooray!!It's available"
else
echo "Oops!!Not available"
fi
grep -q [PATTERN] [FILE] && echo $?
The exit status is 0 (true) if the pattern was found; otherwise blankstring.
if grep -q [string] [filename]
then
[whatever action]
fi
Example
if grep -q 'my cat is in a tree' /tmp/cat.txt
then
mkdir cat
fi
In case you want to checkif the string matches the whole line and if it is a fixed string, You can do it this way
grep -Fxq [String] [filePath]
example
searchString="Hello World"
file="./test.log"
if grep -Fxq "$searchString" $file
then
echo "String found in $file"
else
echo "String not found in $file"
fi
From the man file:
-F, --fixed-strings
Interpret PATTERN as a list of fixed strings, separated by newlines, any of
which is to be matched.
(-F is specified by POSIX.)
-x, --line-regexp
Select only those matches that exactly match the whole line. (-x is specified by
POSIX.)
-q, --quiet, --silent
Quiet; do not write anything to standard output. Exit immediately with zero
status if any match is
found, even if an error was detected. Also see the -s or --no-messages
option. (-q is specified by
POSIX.)
Try this:
if [[ $(grep "SomeString" $File) ]] ; then
echo "Found"
else
echo "Not Found"
fi
I done this, seems to work fine
if grep $SearchTerm $FileToSearch; then
echo "$SearchTerm found OK"
else
echo "$SearchTerm not found"
fi
grep -q "something" file
[[ !? -eq 0 ]] && echo "yes" || echo "no"

How can I use GREP to decide if every line in a file matches my pattern?

I am trying to check if every line in a file matches my pattern (4 characters followed by 4 digits). I tried using GREP with -x -P -v -q options so it returns 1 if my file doesn't match the requirements. I expect it to return nothing in case the file is correct, but it returns nothing even if the file has an error.
$4 is my input file.
My code is:
if [ -f $4 ] && [ `grep -q -P -x -v [[a-z]x{4}/[\dx{4}] $4` ]
then
echo "error"
exit 1
fi
input example:
bmkj2132
ahgc3478
(no uppercase)
Don't check the output of grep, check its exit code.
if [ -f "$4" ] && grep -q ...
Note the double quotes around $4 - otherwise a file name containing whitespace will break the script.
Also, single quote the regex. Square brackets are special in bash and you don't want the regex to suddenly change (expand) when a random filename exists.
Also note that x doesn't mean "times" (under -e, -E, -P neither). The quantifier just follows the quantified with no operator in between:
echo abcd1234 | grep -xP '[a-z]{4}\d{4}'
So, the full condition should be
if [ -f "$4" ] && grep -qvxP '[a-z]{4}\d{4}' "$4" ; then
echo Error >&2
exit 1
fi
Are you sure you want to continue if the file doesn't exist? If not, change the condition to
if ! [ -f "$4" ] || grep ...
BTW, you don't really need the PCRE expression here. If you replace \d by [0-9] or [[:digit:]], you can switch to -E (extended regular expression).
The point about using the exit code of grep is that it does not match the required condition.
Try the following:
if [ -f "$4" ] ; then
wronglines=$(grep -v pattern "$4")
if [ "$wronglines" = "" ] ; then
echo "all is well"
else
echo "a wrong line in the file"
fi
else
echo "cannot even find the file"
fi
This answer describes how we can use grep to search for any line not matching a particular regex pattern. We can modify this to provide a one-liner.
grep -Evq "[1-2]" file.txt && echo "error" && exit 1 || true
On the following file.txt, the error message and exit code will be triggered:
1
2
3
Without || true, this will always have an false return code. Additionally, this only works for the specified use case; modifying exit 1 to something like true will break the one-liner.
The regex pattern included within this example should be modified to the desired pattern.

Linux bash regex global flag

I want to match string with regex and echo matches.
if [[ "${PLUGS}" =~ \"[a-zA-Z0-9.-]+ ]]; then
echo ${BASH_REMATCH[*]}
else
echo "nothing"
fi
But i don't know how to add global flag. If i write regex like /\"[a-zA-Z0-9.-]+/g i get only first match. What i am doing wrong?
EDIT:
Samples data is mysql return of wordpress active plugins SELECT * FROM wp_options WHERE option_name = 'active_plugins';
a:31:{i:0;s:13:"AddMySite.php";i:1;s:19:"akismet/akismet.php";i:2;s:23:"all_in_one_seo_pack.php";i:3;s:16:"authenticate.php";i:4;s:28:"breadcrumb-navigation-xt.php";i:5;s:18:"codeautoescape.php";i:6;s:37:"contact-coldform/contact_coldform.php";i:7;s:32:"custom-query-string-reloaded.php";i:8;s:30:"customizable-post-listings.php";i:9;s:33:"dd-sitemap-gen/dd-sitemap-gen.php";i:10;s:20:"download-counter.php";i:11;s:13:"feedcount.php";i:12;s:13:"full_feed.php";i:13;s:15:"get-weather.php";i:14;s:36:"google-sitemap-generator/sitemap.php";i:15;s:13:"gravatars.php";i:16;s:19:"kill-admin-nags.php";i:17;s:18:"landingsites13.php";i:18;s:30:"nofollow-free/nofollowfree.php";i:19;s:17:"ol_feedburner.php";i:20;s:16:"plugins-used.php";i:21;s:22:"popularity-contest.php";i:22;s:39:"search-everything/search_everything.php";i:23;s:27:"simple-tags/simple-tags.php";i:24;s:26:"simple_recent_comments.php";i:25;s:18:"simple_twitter.php";i:26;s:25:"subscribe-to-comments.php";i:27;s:24:"the-excerpt-reloaded.php";i:28;s:18:"theme-switcher.php";i:29;s:9:"top10.php";i:30;s:16:"wp-db-backup.php";}
If all you want to do is extract all matches and echo them, consider using grep with -o/--only-matching flag:
$ grep -oE '("[a-zA-Z0-9.-]+")' <<<"${PLUGS}"
"AddMySite.php"
"authenticate.php"
"breadcrumb-navigation-xt.php"
"codeautoescape.php"
"custom-query-string-reloaded.php"
"customizable-post-listings.php"
"download-counter.php"
"feedcount.php"
"get-weather.php"
"gravatars.php"
"kill-admin-nags.php"
"landingsites13.php"
"plugins-used.php"
"popularity-contest.php"
"subscribe-to-comments.php"
"the-excerpt-reloaded.php"
"theme-switcher.php"
"top10.php"
"wp-db-backup.php"
We also need to use -E/--extended-regexp, since your regex is POSIX ERE.
Or, to also handle the non-matching case (like in your question):
if ! grep -o -E '"([a-zA-Z0-9.-]+)"' <<<"${PLUGS}"; then
echo "nothing"
fi

Unix using grep with if

This my code
if [[ (grep -x $idle | grep -x $dead | grep -x $busy) || grep -x $idle1 | grep -x $dead | grep -x $busy1 ]] ./Event.log
then
echo "Events are running Successfully" >> ./Event.log
else
echo "One or more Events are down. Check the log and restart the Events." >> ./Event.log
fi
I'm getting the error
0403-057 Syntax error at line 14 : `-x' is not expected.
What's up?
In bash, [[ is syntactically a command which is terminated with the matching ]]. It is not part of the syntax of the if command, whose syntax starts:
if commands ; then
If you want to test whether a command succeeded or not, you just do that:
if grep -q pattern file; then
# grep found pattern in file
else
# grep did not find pattern in file
fi
Within a [[ command, bash expects to find a conditional expression, not another command. That's why grep -x ... is a syntax error. -x is a unary operator in a conditional expression, which is true if its argument is the name of an executable file, but in that expression it is being used as though it were a binary operator.
If you wish to test for more than one pattern with grep, you can use the -e option to specify each option; the grep will succeed (or select) lines matching any of the options:
if grep -q -e pattern1 -e pattern2 file; then
# grep found pattern1 or pattern2 in file
else
# grep did not find either pattern in file
fi
By a long shot, I am guessing that you want Event.log to contain one each of either member of the pairs. This could be done with something like
if awk "/^($idle|$idle1)$/ { ++idle; next }
/^($dead|$dead1)$/ { ++dead; next }
/^($busy|$busy1)$/ { ++busy; next }
idle && dead && busy { exit 0 }
END { exit 1 }' Event.log; then
echo Yes
else
echo no
fi
This collects three variables; if all of them are true, the Awk script exits with a success exit code (that's zero); otherwise, it will return failure (any nonzero value).
It would make more sense to print the result from Awk, too, but there is an awful amount of assumptions and guesswork in this answer already.

Resources