ログファイル内の文字列を検索するシェルスクリプト

ログファイル内の文字列を検索するシェルスクリプト

以下のように、複数のログ ファイルからディレクトリ内の文字列を照合するスクリプトがあります。

#!/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

関連情報