Tengo una secuencia de comandos que coincide con una cadena en un directorio de una cantidad de archivos de registro como se muestra a continuación:
#!/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" {} \;
Esto genera una lista de archivos de registro que contienen la cadena buscada. Por ejemplo:
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
Quiero este resultado como una lista como:
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
Y le pedirá que ingrese el número 1/2/3/4/5/6, lo que abrirá ese archivo numerado, es decir; si presiono 4 enviará el comando
vim /usr/local/tomcat9/logs/localhost_access_log.2017-09-11.txt
y se buscará la cadena "2001NM-100313" en todo ese archivo.
Mi objetivo es leer toda la línea/líneas (puede haber varias líneas con la cadena) que contienen esta cadena de los archivos de registro, puede haber varios archivos de registro que tengan esta cadena con varias fechas, necesito seleccionar cualquier archivo con fecha y leer el registro.
Respuesta1
Simplemente use select
(el bash
incorporado).
$ 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.
$
Entonces el código que deseas probablemente sea:
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
Tenga en cuenta que si sus nombres de archivos contienen espacios en blanco, esto se romperá. Ver también:
Sin embargo, si llama al select
incorporado directamente desde find
, esto manejará los espacios en blanco con facilidad. Entonceslo siguiente es realmente mejoren todos los casos puedo pensar en:
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 {} +
Respuesta2
Leer su pregunta me recordó siempre querer tener un script simple que me facilitara la búsqueda de archivos para una cadena en particular y luego mirar uno de los archivos que contiene la cadena. Basándome en su guión y la sugerencia de saga de usar una matriz, creé mi guión y también terminé el suyo. :)
Tenga en cuenta: este script es /bin/bash, no /bin/sh, porque no sé cómo hacer que la matriz funcione en /bin/sh...
Tu guión:
#!/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
EDITAR: Si bien el script anterior funcionará perfectamente bien para la pregunta original, me he basado en la respuesta de Wildcard, por lo que mi script puede manejar archivos con espacios vacíos y ofrece variosherramientaspara abrir el archivo seleccionado.
Mi guión:
#!/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