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
I'm trying to write a simple function to debug my script easily and making my code simpler. (Still stuck after 3 hours)
I want to pass to this function 3 arguments
A command
A success string
And an error string
The function is supposed to execute the command and print the proper string whether it's a success or not.
What I mean by successful is when the command prints something in the output.
Here is what I've tried (On CentOS7) :
#!/bin/bash
CMD=$(yum list installed | egrep "yum.utils.\w+" | cut -d " " -f1)
SUCCESS="YES"
ERROR="NO"
foo() {
if ["$1" != ""]; then
echo -e "$2"
else
echo -e "$3"
fi
}
foo $CMD $SUCCESS $ERROR
Unfortunately, I'm encountering 2 problems :
Firstly, when the $CMD is empty, the first parameter will be $SUCCESS instead of an empty string (the behaviour I want)
Secondly, I want to remove the console output (> /dev/null 2>&1 ???).
Do you think it's possible? Do you have any idea how to do it?
Otherwise, is there an easier way with the eval command?
Thanks for reading and have a nice day,
Valentin M.
------------------ Correction ------------------
#!/bin/bash
CMD=$(yum list installed | grep -E "yum.utils.\w+" | cut -d " " -f1)
SUCCESS="YES"
ERROR="NO"
foo() {
if [ "$1" != "" ]; then
echo -e "$2"
else
echo -e "$3"
fi
}
foo "$CMD" "$SUCCESS" "$ERROR"
I found out a similar topic here: Stack overflow : How to write a Bash function that can generically test the output of executed commands?
Unfortunately, I'm encountering 2 problems :
Firstly, when the $CMD is empty, the first parameter will be $SUCCESS instead of an empty string (the behaviour I want)
If you follow the suggestion in William Pursell's comment above, this problem is solved, since an empty first parameter is then passed.
Secondly, I want to remove the console output (> /dev/null 2>&1 ???).
I assume by console output you mean the output to STDERR, since STDOUT is assigned to CMD. Your > /dev/null 2>&1 is unsuitable, as it redirects also STDOUT to /dev/null; just do this with STDERR:
CMD=$(yum list installed 2>/dev/null | egrep "yum.utils.\w+" | cut -d " " -f1)
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.
I have the script below that makes a query for the String ERROR generated by HTTP queries, I would like it to check all lines and just return me TRUE for when there is an error or file is empty
result.log
Collecting: LINK1 HTTP 200
EXCEPT ERROR - REST API LINK2 returned HTTP Error
Script:
1 cat /healthcheck/bin/gaps/result.log | grep HTTP | while read line
2 do
3 echo "$line" | grep "ERROR" >/dev/null
4 if [ $? = 0 ]; then
5 RESULT = "TRUE"
6 fi
7 done
8
9 echo $RESULT
Output:
./check.sh: line 5: RESULT: command not found
./check.sh: line 5: RESULT: command not found
Shell check:
$ shellcheck myscript
Line 1:
cat /healthcheck/bin/gaps/result.log | grep HTTP | while read line
^-- SC2148: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.
^-- SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.
^-- SC2162: read without -r will mangle backslashes.
Line 4:
if [ $? = 0 ]; then
^-- SC2181: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.
Line 5:
RESULT = "TRUE"
^-- SC2030: Modification of RESULT is local (to subshell caused by pipeline).
^-- SC1068: Don't put spaces around the = in assignments (or quote to make it literal).
Line 9:
echo $RESULT
^-- SC2031: RESULT was modified in a subshell. That change might be lost.
$
Pipe runs in a subshell. Changes from a subshell are not visible to parent shell. The site bashfaq/024 presents possible workarounds.
You can put break the line if | is the last character on the line, no need to build super long lines for pipelines.
Upper case variables are by convention reserved for exported variables.
cat ... | grep is a useless use of cat. Just grep ... or < file grep.
When you check command return value, just if the command; then instead of the command; if [ $? ....
Use greps exit status in an if. In bash just if <<<"$string" grep -q "pattern"; then. In posix shell do if printf "%s\n" "$string" | grep -q "pattern"; then.
Bash is space aware. The RESULT = "TRUE" executes a command named RESULT with two arguments. It's RESULT="TRUE"
Use while IFS= read -r line to read the whole line exactly.
So while you could:
cat /healthcheck/bin/gaps/result.log |
grep HTTP |
{
while read line
do
echo "$line" | grep "ERROR" >/dev/null
if [ $? -eq 0 ]; then
RESULT="TRUE"
fi
done
echo $RESULT
}
In your case, it's just:
if grep "HTTP" /healthcheck/bin/gaps/result.log | grep -q "ERROR"; then
echo TRUE
fi
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