Shell Script to find string in log file
Solution 1
Reading your question reminded me always wanting to have a simple script that would make it easier for me to search files for a particular string and then look at one of the files containing the string. Building upon your script and the suggestion by saga to use an array, I have created my script and also finished yours. :)
Please note: This script is /bin/bash, not /bin/sh, because I don't know how to get the array working in /bin/sh...
Your script:
#!/bin/bash
# Collect Customer ID as input
read -p "Enter Customer ID: " custid
echo "Searched customer ID $custid found in following logs: "
# Find the customer id as string in specified directory
arr=( $(find /usr/local/tomcat9/logs/ -type f -exec grep -l "$custid" {} \; | sort -r) )
if [ ${#arr[@]} -eq 0 ]; then
echo "No matches found."
else
arr+=('Quit')
select opt in "${arr[@]}"
do
case $opt in
"Quit")
break
;;
*)
vim $opt
break
;;
esac
done
fi
EDIT: While the script above will work perfectly fine for the the original question, I have built upon Wildcard's answer, so my script can handle files with empty spaces and offers various tools to open the selected file.
My script:
#!/bin/bash
# Find string in files of given directory (recursively)
read -p "Enter search string: " text
read -p "Enter directory: " directory
#arr=( $(find $directory -type f -exec grep -l "$text" {} \; | sort -r) )
#find $directory -type f -exec grep -qe "$text" {} \; -exec bash -c '
file=$(find $directory -type f -exec grep -qe "$text" {} \; -exec bash -c 'select f; do echo $f; break; done' find-sh {} +;)
if [ -z "$file" ]; then
echo "No matches found."
else
echo "select tool:"
tools=("nano" "less" "vim" "quit")
select tool in "${tools[@]}"
do
case $tool in
"quit")
break
;;
*)
$tool $file
break
;;
esac
done
fi
Solution 2
Just use select
(the bash
builtin).
$ help select
select: select NAME [in WORDS ... ;] do COMMANDS; done
The WORDS are expanded, generating a list of words. The
set of expanded words is printed on the standard error, each
preceded by a number. If `in WORDS' is not present, `in "$@"'
is assumed. The PS3 prompt is then displayed and a line read
from the standard input. If the line consists of the number
corresponding to one of the displayed words, then NAME is set
to that word. If the line is empty, WORDS and the prompt are
redisplayed. If EOF is read, the command completes. Any other
value read causes NAME to be set to null. The line read is saved
in the variable REPLY. COMMANDS are executed after each selection
until a break command is executed.
$
So the code you want is probably:
read -p 'Enter Customer ID: ' custid
select f in $(find /usr/local/tomcat9/logs -type f -exec grep -q -e "$custid" {} \; -print); do
vim "$f"
done
Note that if your filenames contain whitespace this will break. See also:
However, if you call the select
builtin directly from find
, this will handle whitespace with ease. So the following is actually better in all cases I can think of:
read -p 'Enter customer ID: ' custid
find /usr/local/tomcat9/logs -type f -exec grep -qe "$custid" {} \; -exec bash -c '
select f; do vim "$f"; done' find-sh {} +
Related videos on Youtube
Tasbir
I am a B.Sc Engg graduate in Telecommunication and Electronic Engineering and post graduated in Computer Science. I have served in 2 leading ISPs in Bangladesh worked as System Engineer in a reputed private Bank. Currently I am serving in Karnaphuli Gas Distribution Company Ltd. as Network Administrator. I have a keen thrust to be more and more skilled in Linux environment.
Updated on September 18, 2022Comments
-
Tasbir over 1 year
I have a script that matches a string in a directory from number of log files as below:
#!/bin/sh # Collect Customer ID as input read -p "Enter Customer ID: " custid echo "Searched customer ID $custid found in following logs: " # Find the customer id as string in specified directory find /usr/local/tomcat9/logs/ -type f -exec grep -l "$custid" {} \;
This outputs a list of log files that contains the searched string. For example:
Enter Customer ID: 2001NM-100313 Searched customer ID 2001NM-100313 found in following logs: /usr/local/tomcat9/logs/localhost_access_log.2017-10-04.txt /usr/local/tomcat9/logs/localhost_access_log.2017-07-11.txt /usr/local/tomcat9/logs/localhost_access_log.2017-11-02.txt /usr/local/tomcat9/logs/localhost_access_log.2017-09-11.txt /usr/local/tomcat9/logs/localhost_access_log.2017-08-09.txt /usr/local/tomcat9/logs/localhost_access_log.2017-06-11.txt
I want this output as list like:
1. /usr/local/tomcat9/logs/localhost_access_log.2017-10-04.txt 2. /usr/local/tomcat9/logs/localhost_access_log.2017-07-11.txt 3. /usr/local/tomcat9/logs/localhost_access_log.2017-11-02.txt 4. /usr/local/tomcat9/logs/localhost_access_log.2017-09-11.txt 5. /usr/local/tomcat9/logs/localhost_access_log.2017-08-09.txt 6. /usr/local/tomcat9/logs/localhost_access_log.2017-06-11.txt
And it will ask for the number 1/2/3/4/5/6 to input which will open that numbered file, i.e; if I press 4 it will send command
vim /usr/local/tomcat9/logs/localhost_access_log.2017-09-11.txt
and the string "2001NM-100313" will be searched all over that file.
My target is to read the whole line/lines (there may be multiple lines with the string) that contain this string from the log files, there may be multiple log files that have this string with multiple date, I need to select any dated file and read the log.
-
Wildcard over 6 yearsHint: run
help select
in your bash shell. Also, why in the name of common sense are you usinghead -2
here? -
Johano Fierra over 6 years@Wildcard I am not sure what you are hinting towards, and why the down vote... sure it can be done better, but it does exactly what he wanted.
-
Johano Fierra over 6 yearsI removed the head - 2, it stayed in there from some testing, my bad.
-
Wildcard over 6 yearsI removed the downvote, which was for limiting results to two (with head -2). My hint is about your "always wanting to have a simple script that would make it easier for me to search files for a particular string and then look at one of the files containing the string." That can be done tremendously easily with
select
. Although depending on your workflow,:vimgrep
(from inside Vim) may be more applicable. -
Johano Fierra over 6 years@Wildcard thank you for clarifying. I really like your answer... up-voted. :)
-
Tasbir over 6 yearsThanks @Wildcard This is what exactly I was looking for, thanks a lot. One more thing while I am searching and after finding a list and editing any from the searched file after I close that file the script still waits for another input, how to close the script while I am closing the searched file?