Eu tenho um script que corresponde a uma string em um diretório do número de arquivos de log conforme abaixo:
#!/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" {} \;
Isso gera uma lista de arquivos de log que contém a string pesquisada. Por exemplo:
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
Eu quero essa saída como uma 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
E pedirá a entrada do número 1/2/3/4/5/6 que abrirá aquele arquivo numerado, ou seja; se eu pressionar 4 ele enviará o comando
vim /usr/local/tomcat9/logs/localhost_access_log.2017-09-11.txt
e a string "2001NM-100313" será pesquisada em todo o arquivo.
Meu objetivo é ler toda a linha/linhas (pode haver várias linhas com a string) que contêm essa string dos arquivos de log, pode haver vários arquivos de log que possuem essa string com várias datas, preciso selecionar qualquer arquivo datado e leia o registro.
Responder1
Basta usar select
(o bash
embutido).
$ 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.
$
Então o código que você deseja é provavelmente:
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
Observe que se seus nomes de arquivos contiverem espaços em branco, isso será interrompido. Veja também:
No entanto, se você chamar o select
builtin diretamente de find
, isso irá lidar com espaços em branco com facilidade. Entãoo seguinte é realmente melhorem todos os casos, posso pensar em:
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 {} +
Responder2
Ler sua pergunta me lembrou de sempre querer ter um script simples que tornasse mais fácil para mim pesquisar arquivos para uma string específica e depois olhar para um dos arquivos que contém a string. Com base no seu script e na sugestão da saga de usar um array, criei meu script e também finalizei o seu. :)
Observação: este script é /bin/bash, não /bin/sh, porque não sei como fazer o array funcionar em /bin/sh...
Seu roteiro:
#!/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: Embora o script acima funcione perfeitamente para a pergunta original, desenvolvi a resposta do Wildcard, para que meu script possa lidar com arquivos com espaços vazios e ofereça váriosferramentaspara abrir o arquivo selecionado.
Meu roteiro:
#!/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