Bash counting with GREP - bash

I am trying to find if the word in the file.
If the word is found, it will print 'Found'.
Else 'Not Found'.
But in the process of trying I am confused by the word count of bash.
Can someone help me?
Thank you
#!/bin/bash
a=`grep -c -w $1 /file.txt`
if [ $a > 0 ]
then
echo Found
else
echo Not Found
fi

I suggest:
if grep -q -w "$1" /file.txt; then
From man grep:
Normally the exit status is 0 if a line is selected, 1 if no lines were selected, and 2 if an error occurred. However, if the -q or --quiet or --silent is used and a line is selected, the exit status is 0 even if an error occurred.

Could you please try following, in place of text give your text which are looking into Input_fie, where Input_file is your actual file where you are looking.
if grep -q "text" Input_file
then
echo "text found."
else
echo "Text NOT found"
fi

Related

how to edit this code to show multiple files (it currently works with 1 file)?

I have created a shell script in order to find 2 files. While it works with 1 it does not work with 2 or multiple. Any help?
#!/bin/bash
FILENAME="abc"
if [ -f "${FILENAME}"* ]
then
echo "EXISTS"
else
echo "NOT EXISTS"
fi
Expected: EXISTS
Error:
./test.sh: line 5: [: abc1.sh: binary operator expected
NOT EXISTS
Error is here:
if [ -f "${FILENAME}"* ]
-f option accepts a single file. If there are more files that start
with $FILENAME then * is expanded and more than one file is passed
to -f. It's also reported by shellcheck:
$ ~/.cabal/bin/shellcheck test.sh
In test.sh line 5:
if [ -f "${FILENAME}"* ]
^-- SC2144: -f doesn't work with globs. Use a for loop.
If you want to check if there is at least one file that starts with
$FILENAME without using external tools such as find you need use
for loop like that:
#!/bin/bash
FILENAME="abc"
for file in "${FILENAME}"*
do
if [ -f "$file" ]
then
echo File exists
exit 0
fi
done
echo File does not exist.
exit 1
The simple way is to check if there less then 2 files with same name abc*:
#!/bin/bash
FILENAME="abc"
COUNT_FILES=$(find . -maxdepth 1 -name "$FILENAME*" -type f | wc -l)
if [[ $COUNT_FILES -lt 2 ]]
then
echo "NOT EXISTS"
else
echo "EXISTS"
fi
if ls /path/to/your/files* 1> /dev/null 2>&1
then
echo "files do exist"
else
echo "files do not exist"
fi
This is what I was looking for. What I wanted was a function that looks for single OR multiple files, which the code above performed perfectly. Thanks for the previous answers, much help.

Assistance required for Pre-Commit hook script for SVN to check for TaskID

I have a pre-commit hook script to check for TaskID in log message. I'm unable to make out the logic for same. In Highlighted **if** statement i need a logic to check if first letter of first line is TaskID:(multiple digits)-(space)(log message)
Pre-commit hook:
REPOS="$1"
TXN="$2"
# Check log message for proper task/bug identification
if [ -x ${REPOS}/hooks/check_log_message.sh ]; then
${REPOS}/hooks/check_log_message.sh "${REPOS}" "${TXN}" 1>&2 || exit 1
fi
exit 0
=======>>>>>check_log_message.sh
#!/bin/bash
REPOS="${1}"
TXN="${2}"
SVNLOOK=/usr/bin/svnlook
LOG_MSG_LINE1=`${SVNLOOK} log -t "${TXN}" "${REPOS}" | head -n1`
**if (echo "${LOG_MSG_LINE1}" | egrep '^[T][a][s][k][I][D][:]?[-][1-9]
[\s]*.*$' > /dev/null;) \
|| (echo "${LOG_MSG_LINE1}" | egrep '^[a-zA-Z]+[-][1-9][0-9]*[:]?[\s]*.*$'
> /dev/null;)**
then
exit 0
else
echo ""
echo "Your log message does not contain a TaskID(or bad format used)"
echo "The TaskID must be the first item on the first line of the log
message."
echo ""
echo "Proper TaskID format--> TaskID:xxx- 'Your commit message' "
exit 1
fi
I guess your question concerns using conditionals in Bash.
You can work with the exit codes of programs directly.
For example, if egrep matches something, it exits with code 0 which means success,
otherwise it exits with non-zero,
which means failure.
And you can use this is in conditions, for example:
if command; then
echo success
else
echo failure
fi
Where command can be a pipeline, for example:
if ${SVNLOOK} log -t "${TXN}" "${REPOS}" | head -n1 | egrep -q ^TaskID:
then
exit 0
fi
This means if the first line of the log starts with TaskID:, then exit with 0. Instead of an if statement, you could also use a shorter form with && like this:
${SVNLOOK} log -t "${TXN}" "${REPOS}" | head -n1 | egrep -q ^TaskID: && exit 0
In both examples I used -q with egrep, to suppress the output (the matched line), as I guess you probably don't need it.
The full script with the more complete pattern:
#!/bin/bash
REPOS="${1}"
TXN="${2}"
SVNLOOK=/usr/bin/svnlook
${SVNLOOK} log -t "${TXN}" "${REPOS}" | head -n1 | egrep -q '^TaskID:[0-9][0-9]*- ' && exit 0
echo ""
echo "Your log message does not contain a TaskID(or bad format used)"
echo "The TaskID must be the first item on the first line of the log
message."
echo ""
echo "Proper TaskID format--> TaskID:xxx- 'Your commit message' "
exit 1
Alternatively, I modified my script with help of a colleague.
REPOS="$1"
TXN="$2"
# Make sure that the log message contains some text.
SVNLOOK=/usr/bin/svnlook
LOGMSG=$($SVNLOOK log -t "$TXN" "$REPOS")
# check if any comment has supplied by the commiter
if [ -z "$LOGMSG" ]; then
echo "Your commit was blocked because it have no comments." 1>&2
exit 1
fi
#check minimum size of text
if [ ${#LOGMSG} -lt 15 ]; then
echo "Your Commit was blocked because the comments does not meet minimum length requirements (15 letters)." 1>&2
exit 1
fi
# get TaskID by regex
TaskID=$(expr "$LOGMSG" : '\([#][0-9]\{1,9\}[:][" "]\)[A-Za-z0-9]*')
# Check if task id was found.
if [ -z "$TaskID" ]; then
echo "" 1>&2
echo "No Task id found in log message \"$LOGMSG\"" 1>&2
echo "" 1>&2
echo "The TaskID must be the first item on the first line of the log message." 1>&2
echo "" 1>&2
echo "Proper TaskID format--> #123- 'Your commit message' " 1>&2
exit 1
fi

How do I redirect errors to /dev/null in bash?

We run daily Selenium tests to test our website and extensions. I wrote a script (according to this question) to count the number of passed and failed tests. Here is the script:
#!/bin/bash
today=`TZ='Asia/Tel_Aviv' date +"%Y-%m-%d"`
yesterday=`TZ='Asia/Tel_Aviv' date +"%Y-%m-%d" -d "yesterday"`
...
print_test_results()
{
declare -i passed_tests=0
declare -i failed_tests=0
declare -i total_tests=0
log_suffix="_${file_name}.log"
yesterday_logs="${log_prefix}${yesterday}_[1,2]*${log_suffix}"
today_logs="${log_prefix}${today}_0*${log_suffix}"
for temp_file_name in $yesterday_logs $today_logs ; do
total_tests+=1
if grep -q FAILED "$temp_file_name" ; then
failed_tests+=1
elif grep -q OK "$temp_file_name" ; then
passed_tests+=1
else
failed_tests+=1
fi
done
echo "<tr>"
echo "<td>$test_name - $today</td>"
if [ $passed_tests = "0" ]; then
echo "<td>$passed_tests passed</td>"
echo "<td><span style=\"color: red;\">$failed_tests failed</span></td>"
else
echo "<td><span style=\"color: green;\">$passed_tests passed</span></td>"
echo "<td>$failed_tests failed</td>"
fi
echo "<td>$total_tests tests total</td>"
echo "</tr>"
}
file_name="chrome_gmail_1_with_extension_test"
test_name="Chrome Gmail 1 With Extension Test"
print_test_results
...
But the problem is, if the files are not there (in $yesterday_logs $today_logs), I get error messages. How do I redirect these error messages to /dev/null? I want to redirect them to /dev/null from the script, and not from the line calling the script - I want this script to never show error messages about files which don't exist.
Just for the record:
In general, to suppress error messages in bash, use command 2>/dev/null. So in your case you should use grep -q OK 2>/dev/null.
But as your case also shows (from what I read in the comments) this is a risky thing to do, as it cloaks errors you might have in your code. "I want this script to never print error messages" should only be said when one knows all possible error cases which could possibly occur.
Inside your script you can place this line at start:
shopt -s nullglob
This will not match anything if your glob pattern doesn't find any matching file. Otherwise whole glob pattern is returned when you use something like:
for temp_file_name in $yesterday_logs $today_logs; do ... done
Eventually I changed this line to:
for temp_file_name in `ls $yesterday_logs $today_logs 2>/dev/null` ; do
total_tests+=1
if grep -q FAILED "$temp_file_name" ; then
failed_tests+=1
elif grep -q OK "$temp_file_name" ; then
passed_tests+=1
else
failed_tests+=1
fi
done
Then only the ls errors are directed to /dev/null.

Bash Script - Will not completely execute

I am writing a script that will take in 3 outputs and then search all files within a predefined path. However, my grep command seems to be breaking the script with error code 123. I have been staring at it for a while and cannot really seem the error so I was hoping someone could point out my error. Here is the code:
#! /bin/bash -e
#Check if path exists
if [ -z $ARCHIVE ]; then
echo "ARCHIVE NOT SET, PLEASE SET TO PROCEED."
echo "EXITING...."
exit 1
elif [ $# -ne 3 ]; then
echo "Illegal number of arguments"
echo "Please enter the date in yyyy mm dd"
echo "EXITING..."
exit 1
fi
filename=output.txt
#Simple signal handler
signal_handler()
{
echo ""
echo "Process killed or interrupted"
echo "Cleaning up files..."
rm -f out
echo "Finsihed"
exit 1
}
trap 'signal_handler' KILL
trap 'signal_handler' TERM
trap 'signal_handler' INT
echo "line 32"
echo $1 $2 $3
#Search for the TimeStamp field and replace the / and : characters
find $ARCHIVE | xargs grep -l "TimeStamp: $2/$3/$1"
echo "line 35"
fileSize=`wc -c out.txt | cut -f 1 -d ' '`
echo $fileSize
if [ $fileSize -ge 1 ]; then
echo "no"
xargs -n1 basename < $filename
else
echo "NO FILES EXIST"
fi
I added the echo's to know where it was breaking. My program prints out line 32 and the args but never line 35. When I check the exit code I get 123.
Thanks!
Notes:
ARCHIVE is set to a test directory, i.e. /home/'uname'/testDir
$1 $2 $3 == yyyy mm dd (ie a date)
In testDir there are N number of directories. Inside these directories there are data files that have contain data as well as a time tag. The time tag is of the following format: TimeStamp: 02/02/2004 at 20:38:01
The scripts goal is to find all files that have the date tag you are searching for.
Here's a simpler test case that demonstrates your problem:
#!/bin/bash -e
echo "This prints"
true | xargs false
echo "This does not"
The snippet exits with code 123.
The problem is that xargs exits with code 123 if any command fails. When xargs exits with non-zero status, -e causes the script to exit.
The quickest fix is to use || true to effectively ignore xargs' status:
#!/bin/bash -e
echo "This prints"
true | xargs false || true
echo "This now prints too"
The better fix is to not rely on -e, since this option is misleading and unpredictable.
xargs makes the error code 123 when grep returns a nonzero code even just once. Since you're using -e (#!/bin/bash -e), bash would exit the script when one of its commands return a nonzero exit code. Not using -e would allow your code to continue. Just disabling it on that part can be a solution too:
set +e ## Disable
find "$ARCHIVE" | xargs grep -l "TimeStamp: $2/$1/$3" ## If one of the files doesn't match the pattern, `grep` would return a nonzero code.
set -e ## Enable again.
Consider placing your variables around quotes to prevent word splitting as well like "$ARCHIVE".
-d '\n' may also be required if one of your files' filename contain spaces.
find "$ARCHIVE" | xargs -d '\n' grep -l "TimeStamp: $2/$1/$3"

bash script beep depending on stdout message

Never coded on bash but need something urgent. Sorry if this is not the norm but would really like to get some help.
I have some messages that are thrown to stdout, Depending on the message type (the message is a string with the word "found") I need the bash script to beep.
So far I've come up with this.
output=$(command 1) # getting stdout stream?
while [ true ]; do
if [ "$output" = "found" ]; then # if the stdout has the word "found"
echo $(echo -e '\a') # this makes the beep sound
fi
done
I'm not sure where/how to add grep or awk command to check for the string that has the word "found" and only return "found" so that in the if condition it can check against that word.
Thanks!
You can do something as simple as:
command | grep -q 'found' && echo -e '\a'
If the output of command contains the text "found", then grep will return with a zero exit status, so the echo command will be executed, causing the beep.
If the output does not contain "found", grep will exit with status 1, and will not result in the echo.
Depending on what you need to make the beep work, just replace anything after the &&. The general syntax would be something like:
command | grep -q "$SEARCH" && command_if_found || command_if_not_found

Resources