463

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.

3

16 Answers 16

866
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 
Sign up to request clarification or add additional context in comments.

24 Comments

If I execute this command from bash script how to catch 0 or 1 into a variable ?
@Toren Most recent exit status can be accessed using $?. you can also use the grep command alongside the if statement (as shown in updated answer).
You can use grep -Fqx "$FILENAME" and you don't have to worry about regex characters in the variable contents and you won't have to use them in the search string.
@Toren: Without -F, your filename would be interpreted as a regular expression, not as a normal string. Thus, if it contains strange characters (like .), these will be interpreted by grep's regex engine, and not matched literally. The -x flag ensures that the string matches an entire line, not just a part of it: so if you search for foo, only lines containing exactly foo are matched, not foobar. (There was an error in my examples; it still used some regex syntax. Fixed now.)
A couple of notes for folks looking at this answer: 1) In bash, 0 is always true and anything else is always false 2) Only use the -x flag if you want the entire line to match exactly. If you just want to find if your string exists in the file at all, leave that off. If you want to find if your string exists exactly but without matching an entire line necessarily (i.e., as a whole word), use -w.
|
109

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.) 

1 Comment

-F does not affect the file processing, it affects how PATTERN is interpreted. Typically, PATTERN is interpreted as a regex, but with -F it will be interpreted as a fixed string.
51

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.

4 Comments

Why are the spaces necessary before and after the $file_contenet?
Plus 1 for the fast solution and a more generalizable one
What is the =~ and where can I learn more about it?
@HashimAziz =~ is bash's regex operator. Try stackoverflow.com/a/19441575/2846766 or search for "bash shell regex operator".
40

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.

1 Comment

Is this slower than the other grep solutions mentioned here?
26

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.

2 Comments

or use -q which is same as --quiet :)
agree on the -q also best answer here, and is fourth place. no justice in this world.
12

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 

1 Comment

I would recommend adding -q so that you don't get the found strings in the stdout
8
grep -E "(string)" /path/to/file || echo "no match found" 

-E option makes grep use regular expressions

Comments

6

If I understood your question correctly, this should do what you need.

  1. you can specifiy the directory you would like to add through $check variable
  2. if the directory is already in the list, the output is "dir already listed"
  3. 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

2 Comments

You don't need to test the output of grep, you can just use grep -q and call grep directly from if as Thomas does in his answer. In addition, the question didn't include checking whether the directory exists before adding it to the list (it could be a list of deleted directories, after all).
I removed the example script, it didn't add anything to the answer given by Thomas.
5

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

Comments

4

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 

Comments

4

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 

1 Comment

I don't see -c option in fgrep --help
2

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]" | ... 

Comments

1

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

1 Comment

Uses too much memory in case the file is large. grep -q described in the accepted answer is the most efficient approach.
1
grep -Fxq "String to be found" | ls -a 
  • grep will helps you to check content
  • ls will list all the Files

1 Comment

@ThomWiggers I tried the same and it worked for me.
1

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 

Comments

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.