5217
adb logcatでlogcat.log に特定のパターン(hoge)を持つ行が現われる度に b.sh を実行したいです。  
（hogeがある行を検出する部分と、b.shを起動する部分は書いてみたのですが、「検出毎に実行」という部分がかけずにif ???としています）

```

    #!/bin/bash -v
    #adb Logcatで、あるエラーログがあった（hoge）ことを検出
    adb logcat > logcat.log &
    % tail -f logcat.log | grep hoge
    
    #hogeに該当するログがあれば、b.shを起動
    if ???
    MSG=`./b.sh`
    echo $MSG
    
```
CC BY-SA 3.0
2015-01-24T12:25:14.543
5210
2015-01-26T12:50:09.787
2015-01-26T12:50:09.787
30
7590
question
macos sh
adb logcatでlogcat.log に特定のパターンを持つ行が現われる度に ./b.sh を実行したい
シンプルに、ストリームを受けながらまわす感じにしました。

```

    #!/bin/bash
    
    log_file=logcat.log
    pattern_str=hoge
    found_script=./b.sh
    
    # $log_file を監視して、マッチすれば、$found_script 起動
    tail -f $log_file | while read line
    do
       echo "$line"
       [[ $line == *"$pattern_str"* ]] && $found_script
    done
    
```

スクリプトのテストでは、二つのターミナルを使い、一方から一行づつ打ち込んでください。

Terminal1:

```

    $./logcat_test.sh
    
```

Terminal2:

```

    $cat >> logcat.log
    1: first
    2: second
    3: thirhoge
    4: forth
    
```

Terminal1:

```

    $./logcat_test.sh
    1: first
    2: second
    3: thirhoge
    Script "b.sh" is executed!
    4: forth
    
```

確認できたら、`tail -f $log_file` のところを、`adb logcat` にすれば良いです。
CC BY-SA 3.0
2015-01-24T13:14:00.247
5213
2015-01-24T15:02:20.997
2015-01-24T15:02:20.997
4978
4978
5210
answer
こんな感じでしょうか。

```

    #!/bin/bash
    
    tail -f logcat.log | grep --line-buffered hoge |
    while read line; do
        MSG=`./b.sh`
        echo $MSG
    done
    
```

tail -f logcat.log でリアルタイムに出てきた log を grep して、  
while read line で読めたら読めた時に b.sh を実行しています。

grep は出力をバッファリングするようなので、それを抑えるために  
--line-buffered を付けています。
CC BY-SA 3.0
2015-01-24T13:20:21.807
5214
2015-01-24T13:20:21.807
5288
5210
answer
`logcat.log` に特定のパターンを持つ行が現われる度に `./b.sh`
を実行したいということでしょうか。その要件であれば、以下のワンライナーで可能です。

```

    $ tail -f logcat.log |grep hoge |while read; do ./b.sh; done
    
```

該当する行を表示したい場合は、読み込んだ該当行をシェル変数に取得して渡します。

```

    $ tail -f logcat.log |grep hoge |while IFS= read -r line; do echo -E "$line"; ./b.sh; done
    
```

次の点に注意してください。

  * `read` 実行時に `IFS` に空文字列を設定しているのは入力行の行頭と行末の空白文字を維持するためです。
  * `read` の `-r` オプションは入力行の `\` を解釈させないためのものです。
  * `echo` の `-E` オプションは指定された文字列中の `\` を解釈させないためものもです(`bash` のデフォルトでは不要。`zsh` のデフォルトでは必要)。
  * `echo` に渡す `$line` はダブルクォート `"` で括ってワード展開(空白文字による区切り)や glob 展開(`*` などによるファイル名の展開)を防ぐ必要があります。(`zsh` のデフォルトでは不要)

これらの工夫をしないと該当行が不意に加工されて画面に表示される恐れがあります。

ただし、`grep` は出力をバッファリングするため、出力に一定量の該当行データが溜まらないと `read` が受け取れません。`grep`
に該当行を即座に出力させたいときは `\--line-buffered` オプションを指定します。

```

    $ tail -f logcat.log |grep --line-buffered hoge |while IFS= read -r line; do echo -E "$line"; ./b.sh; done
    
```

以下はコメントを頂いたので追記。

`read` と `echo` の工夫が面倒ということであれば、`tee` を利用します。  
コンソール (tty) に出力するだけでよければ、次のように `/dev/tty` に該当行をコピーすればよでしょう。

```

    $ tail -f logcat.log |grep --line-buffered hoge |tee /dev/tty |while read; do ./b.sh; done
    
```

ただし、これだと続けてパイプラインにページャーなど指定してもデータは渡りません。コンソールに直接出力してるからです。たとえば以下の例はページャー
`less` には何もデータは渡りません。

```

    $ tail -f logcat.log |grep --line-buffered hoge |tee /dev/tty |while read; do ./b.sh; done |less
    
```

直接コンソールに出力したくないなら、次のようにプロセス置換を利用します。これなら `while` のコマンドラインのプロセスと標準出力に該当行が渡ります。

```

    $ tail -f logcat.log |grep --line-buffered hoge |tee >(while read; do ./b.sh; done)
    
```

これなら続けてパイプラインを構築できます。

```

    $ tail -f logcat.log |grep --line-buffered hoge |tee >(while read; do ./b.sh; done) |less
    
```

もしプロセス置換が使えないシェルであれば、次のようにします。

```

    $ (tail -f logcat.log |grep --line-buffered hoge |tee /proc/self/fd/3 |while read; do ./b.sh; done) 3>&1|less
    
```
CC BY-SA 3.0
2015-01-24T13:59:21.583
5217
2015-01-25T04:20:29.757
2015-01-25T04:20:29.757
3061
3061
5210
answer