8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

grepとpecoによる順次絞り込みするシェルスクリプト

Last updated at Posted at 2015-02-04

名付けてgrepeco

peco/peco: Simplistic interactive filtering tool

色んなデータを柔軟に絞り込みしたい

各種のデータをパイプで処理するとき、適当にワードで絞り込んでからpecoでインクリメンタルサーチしたいことがよくある。これを簡単にできるようにしたい。

想定される用途はこんな感じ。

$ ls | grepeco hoge

パイプで与えられたデータを、ターミナルから入力された文字列で絞り込む。

パイプからの入力とターミナルからの入力を区別する

ここで、パイプで与えられたデータとはシェルスクリプトの標準入力、ターミナルから入力された文字列とは引数である。

シェルスクリプト内において、この二つは以下のように得ることができる。

# 標準入力を得る
cat -
# 引数を得る
echo "$1" # 1つめ
echo "$*" # すべて(1つの文字列として)
for i in "$@" # すべて(配列として)
do
  echo "arg: $i"
done

この場合、引数を配列として扱うのであれば、複数の検索語による、複数の検索結果からさらに絞り込むことができる。

コード

以上を踏まえて、コードは以下のようになる。

grepeco.sh
#!/bin/bash
# 引数を単一の文字列として扱う
# 変数を初期化
pipes=()
prompt="select stdin from pipe"
optm=""
usage () {
  echo "Usage: grepeco [-1h] [-p prompt] <args>" 1>&2
  echo "  -1: find only one" 1>&2
  echo "  -p: change peco prompt" 1>&2
  echo "  -h: view help" 1>&2
}
while getopts "1p:h" OPT
do
  case $OPT in
    1)
      optm="m1" # grepのオプションを変更
      ;;
    p)
      prompt="$OPTARG" # pecoのプロンプトを変更
      ;;
    h)
      usage
      exit 0
      ;;
    ?)
      echo "ERROR: Undifined option" 1>&2
      usage
      exit 1
      ;;
  esac
done
shift $(($OPTIND - 1))
if [ -p /dev/stdin ];then # パイプ入力があるか判断
  while read pipe
  do
    pipes+=("$pipe")
  done < <(if [ -n "$1" ]; then # 引数があるか判断
    cat - | grep -i"$optm" "$*"
  else
    cat -
  fi)
else
  echo "ERROR: No stdin from pipe" 1>&2
  exit 1
fi
case  "${#pipes[@]}" in # pipesの要素数による分岐
  0 )
    echo "ERROR: No hit." 1>&2
    exit 1
    ;;
  1)
    echo "${pipes[*]}"
    ;;
  *)
    for i in "${pipes[@]}"
    do
      echo "$i"
    done | peco --prompt "$prompt"
    ;;
esac
grepeco.sh
#!/bin/bash
# 引数を配列として扱う
-  done < <(if [ -n "$1" ]; then
-    cat - | grep -i"$optm" "$*"
-  else
-    cat -
-  fi)

+  done < <(if [ -n "$1" ]; then
+    stdin="$(cat -)" # ループで標準出力がリセットされるため変数に格納
+    for arg in "$@"
+    do
+      echo "$stdin" | grep -i "$arg"
+    done | sort -u # 重複する結果を削除
+  else
+    cat -
+  fi)

if文の結果をwhile文に渡すということを思いついてコードがシンプルになった。

参考

8
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?