『〇〇というファイルの、▲▲という行の下に、■■と追記』を自動化し簡単に再現したい


Qiitaの記事や、各種チュートリアルを見てると掲題の表現がしばしば現れる

Qiitaでいうと、下記のような表現を見かける。

package.json
  "scripts": {
  "watch:server": "browser-sync init", // 追加
  ...

プロジェクト作成時に共通な部分は再利用したい

チュートリアル後に「なんか作ってみよう」とした時に、共通の設定部分とかまた設定したりするのは一苦労しますよね。
今後もプロジェクトの初期化時に再利用できる部分は再利用したいなー、って思うことあるんじゃないでしょうか(ありますよね...?
※再利用するまでの共通設定にある程度時間がかかる想定でいます。
ここで、再利用の方法は多々あると思うので、いくつか思いついた方法をメモしておきます。
最終的に2の方法「初期化スクリプトを利用する方法(★部分)」で進めていきます。

プロジェクトの再利用方法

  1. ある程度チュートリアルを終えた状態のプロジェクトなどをコピーして保存、今後はそれをコピーしてプロジェクトを作成する方法
  2. プロジェクトで行う手順を、shellscriptなどで自動化し、プロジェクト作成時にそのスクリプトを実行する方法★
  3. 何度もコマンドを使い体に覚え込ませることで、脳内キャッシュを利用する方法

それぞれの再利用方法の特徴

  1. シンプルなコピー
    • もっともシンプルで強力な方法
    • 実行環境が変わった場合に弱め e.g. ビルド結果のファイルが環境依存, コピーするファイル多い
    • 出来上がった環境はコピーできるが、システムに行った変更などをコピーし忘れる恐れがある
  2. 初期化スクリプトを利用する方法★
    • ファイルをちょこっと変更するなどの、手動では簡単な操作ですら、自動化するのは億劫
    • ビルドは実行するマシンごとに行われるので、1の方法よりは環境依存が少ない(もちろんないという意味ではない)
  3. 体育会系な方法
    • 脳内キャッシュ少なめだときつい(言い訳

どうやって実現するか

Linuxのsed(Stream EDitor)コマンドを用いて、特定行を編集する!!

先人方の「いや、それだけ?」って声が聞こえてきます。
もう少々先にある本題を読んでも、同じことを思うかもしれませんがご容赦ください(逃げ

『〇〇というファイルの、▲▲という行の下に、■■と追記』をsedで自動化した例

『「package.json」というファイルの、「 "scripts": {」という行の下に、「"watch:server": "browser-sync init",」と追記』と読み替えて、みましょう。
早速sedで書いてみましょう。

sedによる文字列追加の構文
sed -e "/▲▲/a ■■" 〇〇 -i

簡単やん、って思いました。(フラグ

残念なsed(そのまま入れてみた)
sed -e "/    "scripts": {/a "watch:server": "browser-sync init"," package.json -i

動かない...!!(迫真

「いや、ダブルクォートをエスケープしなさい」って聞こえてきそうです。

バックスラッシュをつけてダブルクォートをエスケープしてみる。

sed(ダブルクォートの前に\つけてエスケープしてみた)
sed -e "/    \"scripts\": {/a \"watch:server\": \"browser-sync init\"," package.json -i

追加されたっ...!!

このsed作るだけで達成感感じてしまい、チュートリアルの続きができない

このsedを簡単に生成したくなりました

この黒魔術的なファイルを作成します。

/usr/local/bin/add
target=`echo $1| sed -e "s/\"/\\\\\\\\\"/g"`
addText=`echo $2| sed -e "s/\"/\\\\\\\\\"/g"`
file=`echo $3| sed -e "s/\"/\\\\\\\\\"/g"`
sed -e "/${target}/a ${addText}" ${file}

echo "sed -e \"/${target}/a ${addText}\" ${file} -i"

実行権限を与えてあげます。

chmod +x /usr/local/bin/add
使い方
//add '■■' '▲▲' '〇〇'
add '  "scripts": {' '"watch:server": "browser-sync init",' package.json 
//すると下記のsedが出力されます(ついでにsedによる変換例も出力されます)
//sed -e "/\"scripts\": {/a \"watch:server\": \"browser-sync init\"," package.json -i

まとめ

使い方、の部分に書いた方法で、エスケープにかかるひと手間をなくしてくれるスクリプトを作りました。
追記の方法だけ作成しましたが、変更に関しても同様の方法で実装できると思います。
より良い方法等ご存知でしたら、ご教授いただけると幸いです。

備考 Macのsedの場合

BSD系のsedは,Linuxのものと別の挙動をするため
GNUのsedをインストールするといいかも。

brew install gnu-sed

gnu-sedをsedコマンドとして使うようにする場合は.bashrcにPATH追記

.bashrc
//下記を追記
export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"