shellでプロジェクト内のテキストを一括置換する

  • shell

素朴にやる

rgsed を組み合わせれば実現できる。

$ rg FOO -l | xargs sed -i s/FOO/BAR/g

( ripgrepでgrep検索しつつsedで一括置換をかける | 7me を読みました、ありがとうございます)

素朴に関数化する

いちいちパイプでコマンド繋いで~パターン2回書いて~とやってられないので、こういう関数を .zshrc などに書いておくと一応シュッと呼べる。

rp() {
  rg $1 -l | xargs sed -i s/$1/$2/g
}
$ rp print println
# ... (特に何も出ない)

多少いい感じに関数化する

上記の例だと何も表示されないままスッ…と置換されて寂しいので、いい感じに経過・結果が分かるようにする。

あと、自分は絶対に引数を忘れて呼んだりマッチしないパターンを書いたりするので、それにも備えを打つ。

rp() {
  if [ -z "$1" ] || [ -z "$2" ]; then
    echo "USAGE: rp PATTERN REPLACEMENT"
  else
    MATCHED_FILES=`rg $1 -l`
    FILES_COUNT=`echo $MATCHED_FILES | wc -l`
    if [ -z "$MATCHED_FILES" ]; then
      echo "No files matched."
    fi

    echo $MATCHED_FILES

    while :
    do
      read "FLAG?$FILES_COUNT file(s) changed (y/n): "
      if [ $FLAG = "y" ]; then
        echo $MATCHED_FILES | xargs sed -i s/$1/$2/g
        echo "success🦎"
        break
      elif [ $FLAG = "n" ]; then
        echo "canceled"
        break
      else
        echo "enter y or n."
      fi
    done
  fi
}
$ rp print println
d.py
a.py
b.py
c.py
4 file(s) changed (y/n):
enter y or n.
4 file(s) changed (y/n): y
success🦎

やったね。

(シェルは本当に自信がないのでもっとマシな書き方を知っている方がいれば助けてください…)