Bashで長いコマンドを組み立てる時に使っているTips


TerraformやAnsibleなどを使って、同じ環境を構築したり、削除したり、変更したりを何度も繰り返しながら進めることが多いのですが、色々な環境とか要件とか、自分のやりたいことをやろうとするとコマンドが長くなってしまうことがあります。

毎回書くのも面倒、コピペも同じくらい面倒。ターミナルから出たくない。

何か大げさに作らなくても、自分でちょっとラップしたい時にササッと作れる、かつ開発中なんかに便利なように簡単にかつインタラクティブにできるTipsです。

まずはBashのselect

まずBashのselectです。
例えば、以下のようなフォルダ構造を持っているリポジトリで、インタラクティブにディレクトリを引数に指定したいとします。

services/
├── servcie_A
├── servcie_B
├── servcie_C
├── servcie_D
├── servcie_E
├── servcie_F
└── servcie_G

以下のようにselectを活用すると使いやすいです。

SERVICE_DIR=./services
services=$(ls -1 ${DEPLOY_DIR})
echo ""
echo "select deployment:"
select var in $service
do
  if [ "${REPLY}" = "q" ]; then
    echo "QUIT."
    exit -1
  fi

  if [ -n "${var}" ]; then
    break
  else
    echo "invalid selection."
  fi
done
echo $service

数字で選べるのが気に入っています。入力ミスが少ないですし、数字+Enterで選んでいけるこの方式が好きです。個人的には選択肢が10個くらいまではこれが使いやすいです。

select deployment:
1) servcie_A  3) servcie_C  5) servcie_E  7) servcie_G
2) servcie_B  4) servcie_D  6) servcie_F
#? 6
servcie_F

選択肢10個くらいと書きましたが、そこまで遭遇することは無いものの、選択肢が多くなってしまう場合があります。

そうすると、このやり方は辛いです。

select deployment:
 1) servcie_A1  17) servcie_F2  33) servcie_K3  49) servcie_Q1  65) servcie_V2
 2) servcie_A2  18) servcie_F3  34) servcie_L1  50) servcie_Q2  66) servcie_V3
 3) servcie_A3  19) servcie_G1  35) servcie_L2  51) servcie_Q3  67) servcie_W1
 4) servcie_B1  20) servcie_G2  36) servcie_L3  52) servcie_R1  68) servcie_W2
 5) servcie_B2  21) servcie_G3  37) servcie_M1  53) servcie_R2  69) servcie_W3
 6) servcie_B3  22) servcie_H1  38) servcie_M2  54) servcie_R3  70) servcie_X1
 7) servcie_C1  23) servcie_H2  39) servcie_M3  55) servcie_S1  71) servcie_X2
 8) servcie_C2  24) servcie_H3  40) servcie_N1  56) servcie_S2  72) servcie_X3
 9) servcie_C3  25) servcie_I1  41) servcie_N2  57) servcie_S3  73) servcie_Y1
10) servcie_D1  26) servcie_I2  42) servcie_N3  58) servcie_T1  74) servcie_Y2
11) servcie_D2  27) servcie_I3  43) servcie_O1  59) servcie_T2  75) servcie_Y3
12) servcie_D3  28) servcie_J1  44) servcie_O2  60) servcie_T3  76) servcie_Z1
13) servcie_E1  29) servcie_J2  45) servcie_O3  61) servcie_U1  77) servcie_Z2
14) servcie_E2  30) servcie_J3  46) servcie_P1  62) servcie_U2  78) servcie_Z3
15) servcie_E3  31) servcie_K1  47) servcie_P2  63) servcie_U3
16) servcie_F1  32) servcie_K2  48) servcie_P3  64) servcie_V1
#? 

pecoの助けを借りる

こういう時、私の場合は、長いことお世話になっているpecoの助けを借ります。

コードはかなり簡潔になります。

Bash以外を使うことになるのですが、1バイナリ置いておくだけで動くのでありだと思っています。

PECO_EXE=./peco
SERVICE_DIR=./services
svc=$(ls -1 ${SERVICE_DIR} | ${PECO_EXE})
echo ${svc}

pecoを使えば先程のような大量の選択肢も、

クエリで楽々選択できます。

最後には確認を入れる

TerraformやAnsibleの実行先を間違えると、例え開発環境で本番に影響無くても、時間もお金もかかるので最後に確認プロンプトは入れるようにしています。

ここはselect使ってます。

echo ""
echo "Your selection:"
echo "Service-> ${service}"
echo "Variable-> ${var}"
echo "Operation-> ${op}"
select isOk in ok exit
do
  if [ -n "${isOk}" ]; then
    if [ "ok" == "${isOk}" ]; then
      break
    elif [ "exit" == "${isOk}" ]; then
      echo "EXIT!"
      exit -1
    fi
  else
    echo "invalid selection."
  fi
done

こんな感じです。開発中などは慣れてくると間違って実行してしまうこともあるのですが、無いよりはマシかと思っています。

Your selection:
Service-> servcie_C2
Variable-> myenv.tfvars
Operation-> apply
1) ok
2) exit
#? 

使い古された方法だと思いますが、ちょうどこのTipsを紹介する機会があったので書いておきました。