How to test if string exists in file with Bash?
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
How do I find files that do not contain a given string pattern?
How do I find out the files in the current directory which do not contain the word foo (using grep )?
18 Answers 18
If your grep has the -L (or —files-without-match ) option:
@GuruM This can be done in GNU grep by exporting the variable GREP_OPTIONS=’—exclude-dir=.svn —exclude-dir=.git’ :^)
You can do it with grep alone (without find).
This is the explanation of the parameters used on grep
-L, --files-without-match each file processed. -R, -r, --recursive Recursively search subdirectories listed. -i, --ignore-case Perform case insensitive matching.
If you use l (lowercased) you will get the opposite (files with matches)
-l, --files-with-matches Only the names of files containing selected lines are written
Take a look at ack . It does the .svn exclusion for you automatically, gives you Perl regular expressions, and is a simple download of a single Perl program.
The equivalent of what you’re looking for should be, in ack :
The following command gives me all the files that do not contain the pattern foo :
find . -not -ipath '.*svn*' -exec grep -H -E -o -c "foo" <> \; | grep 0
You want to change the grep 0 at the end to grep 0$ (otherwise you get erroneous matches on files that have the character 0 in their filename).
@clouseau is mostly right. However, grep ‘0$’ would match files with multiples of 10 lines too! You need grep ‘:0$’ at the end to check for an explicit ‘:0’ at the end of the line. Then you will only get files with zero lines matched.
The UNIX I’m on didn’t have versions of find or grep with these options, so I had to go with the «ack» command suggested in other comments.
Highly inneficcient, as find will have to look for all the files, including those containing «foo», to then discard them on a second process. Will not work well for a big number of files being sought. A solution using an inbuilt find argument should be offered instead.
The following command excludes the need for the find to filter out the svn folders by using a second grep .
If you are using git, this searches all of the tracked files:
and you can search in a subset of tracked files if you have ** subdirectory globbing turned on ( shopt -s globstar in .bashrc, see this):
find . -not -ipath '.*svn*' -exec grep -H -E -o -c "foo" <> \; | grep :0\$
For completeness the ripgrep version:
rg --files-without-match "pattern"
You can combine with file type and search path, e.g.
rg --files-without-match -t ruby "frozen_string_literal: true" app/
grep -H -E -o -c "foo" */*/*.ext | grep ext:0
My attempts with grep -v just gave me all the lines without «foo».
I need to refactor a large project which uses .phtml files to write out HTML using inline PHP code. I want to use Mustache templates instead. I want to find any .phtml giles which do not contain the string new Mustache as these still need to be rewritten.
find . -iname ‘*.phtml’ -exec grep -H -E -o -c ‘new Mustache’ <> \; | grep :0$ | sed ‘s/..$//’
Explanation
find . Find files recursively, starting in this directory
-iname ‘*.phtml’ Filename must contain .phtml (the i makes it case-insensitive)
-exec ‘grep -H -E -o -c ‘new Mustache’ <>‘ Run the grep command on each of the matched paths
-H Always print filename headers with output lines.
-E Interpret pattern as an extended regular expression (i.e. force grep to behave as egrep).
-o Prints only the matching part of the lines.
-c Only a count of selected lines is written to standard output.
This will give me a list of all file paths ending in .phtml , with a count of the number of times the string new Mustache occurs in each of them.
$> find . -iname '*.phtml$' -exec 'grep -H -E -o -c 'new Mustache' <>'\; ./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0 ./app/MyApp/Customer/View/Account/studio.phtml:0 ./app/MyApp/Customer/View/Account/orders.phtml:1 ./app/MyApp/Customer/View/Account/banking.phtml:1 ./app/MyApp/Customer/View/Account/applycomplete.phtml:1 ./app/MyApp/Customer/View/Account/catalogue.phtml:1 ./app/MyApp/Customer/View/Account/classadd.phtml:0 ./app/MyApp/Customer/View/Account/orders-trade.phtml:0
The first pipe grep :0$ filters this list to only include lines ending in :0 :
$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' <> \; | grep :0$ ./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0 ./app/MyApp/Customer/View/Account/studio.phtml:0 ./app/MyApp/Customer/View/Account/classadd.phtml:0 ./app/MyApp/Customer/View/Account/orders-trade.phtml:0
The second pipe sed ‘s/..$//’ strips off the final two characters of each line, leaving just the file paths.
$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' <> \; | grep :0$ | sed 's/..$//' ./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml ./app/MyApp/Customer/View/Account/studio.phtml ./app/MyApp/Customer/View/Account/classadd.phtml ./app/MyApp/Customer/View/Account/orders-trade.phtml
Bash checking if string does not contain other string
It’s a inversed duplicate: read this answer and use else or not like in: if ! stringContain «c0» «$myteststring» ;then .
3 Answers 3
if [[ $ != *"c0"* ]];then # testmystring does not contain c0 fi
See help [[ for more information.
I agree they’re superfluous for the mere example shown above. But if the variable name and the pattern string are getting more complex (e.g.: containing space in the pattern string), quoting them is necessary. Anyway, quoting them usually does no harm. 🙂
True it does no harm, and if you enjoy typing them then knock yourself out! Sorry, I know this is pedantic, its just that I find people often use things like < >by rote without understanding when they are needed and when they are not (I did upvote you).
@cdarke: as far as i know not using <> incurs in a performance penalty because the shell cannot immediately assume it is a variable while with it, it can. I am not completely absolutely sure and worse i cant remember where I saw the numbers.
@Randyman99: while I agree with your aim, I don’t believe that adding superfluous characters when you don’t understand what they do develops good programming practice. That’s my point — too many people use them because of a cargo culture and they never learn what they are actually for — that’s not good programming practice. Defensive programming is good, mindless programming is not good. Take that from someone who has been programming professionally for fifty years.