Typoしたものが大半なのだけど、指定した文字列とN文字違ったり、1文字ずれている(「あいうえお」→「いあうえお」みたいな)文字列をヒットさせたいということがごくごくたま~にあって、それをgrepでときどきやっている。 個人のマシンではfunctionを作ってあるのだけど、たま~にリモートマシンで使うとき(+ローカルのrcファイルを読み込ませてない時)なんかにはその場でコマンドを組み合わせたりしているので、備忘で残しておく。

1文字違う文字列をgrepする

指定した文字列から1文字違う文字列をgrepする場合、以下のようにする。

echo 検索対象文字列 | grep -f <(echo 検索文字列 | grep -o . | awk '{a=$0=a$0}END{for(i=1;i<=NR;i++){print gensub(/./,".",i)}}')
blacknon@BS-PUB-UBUNTU-01:~$ echo これはあいんえお | grep -f <(echo あいうえお | grep -o . | awk '{a=$0=a$0}END{for(i=1;i<=NR;i++){print gensub(/./,".",i)}}')
これはあいんえお

何しているのかを簡単に記述したのが以下。

# grep -f <()で、()内で生成した文字列をファイルとして読み込ませる
grep -f <(
    echo 検索文字列 | \
        # 検索文字列を1文字づつに分解 \
        grep -o . | \
        # 各文字が「.」の組み合わせを生成(「あいう」→「.いう」「あ.う」「あい.」) \
        gawk '
            {a=$0=a$0}
            END{
                for(i=1;i<=NR;i++){
                    print gensub(/./,".",i)
                }
            }'
    )

1文字ずれている文字列をgrepする

似たようなやり方で、1文字ずれている文字列についてもgrepを行える(Macの場合はgsedを使う必要あり)。

echo 検索対象文字列 | grep -f <(STR="検索文字列";for i in $(seq 0 $((${#STR}-1)));do sed -r 's/(.{'$i'})(.)(.)/\1\3\2/' <<<$STR;done)
blacknon@BS-PUB-UBUNTU-01:~$ echo うんこ | grep -f <(STR="うこん";for i in $(seq 0 $((${#STR}-1)));do sed -r 's/(.{'$i'})(.)(.)/\1\3\2/' <<<$STR;done)
うんこ

これも、何をしているのかを一応コメント付きのものを載せておく。

# grep -f <()で、()内で生成した文字列をファイルとして読み込ませる
grep -f <(
    STR="検索文字列"
    # forで文字列の位置を1文字ずつずらす
    for i in $(seq 0 $((${#STR}-1)));do
        # sedで$i分だけ文字列を無視して置換(\2と\3の位置をずらす)
        sed -r 's/(.{'$i'})(.)(.)/\1\3\2/' <<<$STR;
    done
    )

どちらも一発で検索させる

どちらも一発で出す場合、ちょっと乱暴だけど以下のようにしとけばいい。 (ちゃんと書くなら変数にしてfunctionにしたほうがいいと思うけど…(´・ω・`))

echo 検索対象文字列 | grep -f <(cat <(STR="検索文字列";for i in $(seq 0 $((${#STR}-1)));do sed -r 's/(.{'$i'})(.)(.)/\1\3\2/' <<<$STR;done) <(echo 検索文字列 | grep -o . | awk '{a=$0=a$0}END{for(i=1;i<=NR;i++){print gensub(/./,".",i)}}'))
blacknon@BS-PUB-UBUNTU-01:~$ echo これはあたうえお | grep -f <(cat <(STR="あいうえお";for i in $(seq 0 $((${#STR}-1)));do sed -r 's/(.{'$i'})(.)(.)/\1\3\2/' <<<$STR;done) <(echo あいうえお | grep -o . | awk '{a=$0=a$0}END{for(i=1;i<=NR;i++){print gensub(/./,".",i)}}'))
これはあたうえお

functionにしたものはここにおいてあるので、もし使う場合はそれを利用するといいだろう。