以下のように、複数のログ ファイルからディレクトリ内の文字列を照合するスクリプトがあります。
#!/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
あなたの質問を読んで、ファイル内で特定の文字列を検索し、その文字列を含むファイルの 1 つを簡単に確認できる簡単なスクリプトがずっと欲しかったことを思い出しました。あなたのスクリプトと、配列を使用するという saga の提案に基づいて、私は自分のスクリプトを作成し、あなたのスクリプトも完成させました。 :)
注意: このスクリプトは /bin/sh ではなく /bin/bash です。/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