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 asgrep
,cmp
, anddiff
, 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
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"
.
I just had the same problem and found a surprisingly understandable solution which does not require any regex knowledge.
This works in Bash and ksh, and in zsh with setopt kshglob
:
WORD=abc
[[ "$WORD" == @(def|abc|ghi|foo|barbaz) ]] && echo Word is in set.
(Native zsh version would be the same without the @
sign).
How does this work? I don’t want to repeat large portions of the bash manual here, but in my own words:
If the binary operator ==
is used with the compound command [[
, the word to the right side of the operator undergoes pattern matching as explained in the section «Pattern Matching» in the bash manual. Furthermore, under these conditions, while matching, the shell option extglob
is assumed to be set (regardless of the actual setting); this is the key point in understanding the above.
But what if the words in your set already contain characters which have a special meaning in pattern matching, command substitution and other expansions? The remedy is easy: Just use something like
[[ "$WORD" == @('a*'|abc|'?ghi'|'$DontExpandMe'|barbaz) ]] && echo Word is in set.
I found this to be a very easy, understandable and efficient (as long as $WORD
is short) solution which does not have side effects or is dangerous like the set
-based methods.
To check if a directory exists in a shell script, you can use the following:
if [ -d "$DIRECTORY" ]; then
# Control will enter here if $DIRECTORY exists.
fi
Or to check if a directory doesn’t exist:
if [ ! -d "$DIRECTORY" ]; then
# Control will enter here if $DIRECTORY doesn't exist.
fi
However, as Jon Ericson points out, subsequent commands may not work as intended if you do not take into account that a symbolic link to a directory will also pass this check.
E.g. running this:
ln -s "$ACTUAL_DIR" "$SYMLINK"
if [ -d "$SYMLINK" ]; then
rmdir "$SYMLINK"
fi
Will produce the error message:
rmdir: failed to remove `symlink': Not a directory
So symbolic links may have to be treated differently, if subsequent commands expect directories:
if [ -d "$LINK_OR_DIR" ]; then
if [ -L "$LINK_OR_DIR" ]; then
# It is a symlink!
# Symbolic link specific commands go here.
rm "$LINK_OR_DIR"
else
# It's a directory!
# Directory command goes here.
rmdir "$LINK_OR_DIR"
fi
fi
Take particular note of the double-quotes used to wrap the variables. The reason for this is explained by 8jean in another answer.
If the variables contain spaces or other unusual characters it will probably cause the script to fail.
#!/usr/bin/env bash
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
is a useful one-liner which will give you the full directory name of the script no matter where it is being called from.
It will work as long as the last component of the path used to find the script is not a symlink (directory links are OK). If you also want to resolve any links to the script itself, you need a multi-line solution:
#!/usr/bin/env bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
This last one will work with any combination of aliases, source
, bash -c
, symlinks, etc.
Beware: if you cd
to a different directory before running this snippet, the result may be incorrect!
Also, watch out for $CDPATH
gotchas, and stderr output side effects if the user has smartly overridden cd to redirect output to stderr instead (including escape sequences, such as when calling update_terminal_cwd >&2
on Mac). Adding >/dev/null 2>&1
at the end of your cd
command will take care of both possibilities.
To understand how it works, try running this more verbose form:
#!/usr/bin/env bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
TARGET="$(readlink "$SOURCE")"
if [[ $TARGET == /* ]]; then
echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
SOURCE="$TARGET"
else
DIR="$( dirname "$SOURCE" )"
echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
if [ "$DIR" != "$RDIR" ]; then
echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"
And it will print something like:
SOURCE './scriptdir.sh' is a relative symlink to 'sym2/scriptdir.sh' (relative to '.')
SOURCE is './sym2/scriptdir.sh'
DIR './sym2' resolves to '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
DIR is '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
bash check if string in file
Comment
1
Popularity
9/10 Helpfulness
4/10
Language
shell
Source: Grepper
Tags: bash
file
shell
Contributed on Nov 11 2020
Armandres
0 Answers Avg Quality 2/10
Closely Related Answers
bash if file contains string
Comment
1
Popularity
9/10 Helpfulness
8/10
Language
shell
Source: stackoverflow.com
Tags: bash
Contributed on Mar 24 2020
Witty Wolf
0 Answers Avg Quality 2/10
check if file contains string bash
Comment
0
Popularity
1/10 Helpfulness
1/10
Language
shell
Source: Grepper
Tags: bash
contains
file
shell
string
Contributed on May 21 2022
Difficult Dogfish
0 Answers Avg Quality 2/10