У меня есть скрипт, который сопоставляет строку в каталоге из нескольких файлов журнала, как показано ниже:
#!/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" {} \;
Это выводит список файлов журнала, содержащих искомую строку. Например:
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
Я хочу, чтобы этот вывод был в виде списка:
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
И он попросит ввести число 1/2/3/4/5/6, которое откроет этот пронумерованный файл, т.е. если я нажму 4, он отправит команду
vim /usr/local/tomcat9/logs/localhost_access_log.2017-09-11.txt
и строка «2001NM-100313» будет найдена по всему файлу.
Моя цель — прочитать всю строку/строки (строок со строкой может быть несколько), которые содержат эту строку из файлов журнала. Может быть несколько файлов журнала, которые содержат эту строку с несколькими датами. Мне нужно выбрать любой файл с датой и прочитать журнал.
решение1
Просто используйте select
( bash
встроенную функцию).
$ 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.
$
Итак, код, который вам нужен, вероятно, следующий:
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
Обратите внимание, что если имена файлов содержат пробелы, это приведет к сбою. Смотрите также:
Однако если вы вызовете select
встроенную функцию напрямую из find
, она легко справится с пробелами. Так чтоследующее на самом деле лучшево всех случаях, которые приходят мне на ум:
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 {} +
решение2
Прочитав ваш вопрос, я вспомнил, что всегда хотел иметь простой скрипт, который бы упростил мне поиск файлов для определенной строки, а затем просмотр одного из файлов, содержащих эту строку. Основываясь на вашем скрипте и предложении saga использовать массив, я создал свой скрипт и также закончил ваш. :)
Обратите внимание: этот скрипт — /bin/bash, а не /bin/sh, потому что я не знаю, как заставить массив работать в /bin/sh...
Ваш сценарий:
#!/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
ПРАВКА: Хотя приведенный выше скрипт отлично подойдет для исходного вопроса, я основывался на ответе Уайлдкарда, поэтому мой скрипт может обрабатывать файлы с пустыми пространствами и предлагает различныеинструментычтобы открыть выбранный файл.
Мой сценарий:
#!/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