ローカル環境において、手動でHTTPリクエストや(Postgre)SQLを実行するのが辛くなってきたため、それらを自動化するBashスクリプトを書いてみました。
今回はこのスクリプトを解説いたします。
想定している環境
- ローカル環境
- DBサーバ(PostgreSQL)がDocker上に存在
必要なライブラリのチェック
スクリプトではdocker、psql、jq、curlを使用しているため、これらがインストールされているかをチェックします。
各ライブラリの名前を、for文のin
に列挙しています。which
コマンドでエラーが出力された場合、usage()
を呼び出し、標準出力は捨てています。
function usage(){echo"please install docker, psql, jq, and curl"exit 1
}# check requirementsfor libName in docker psql jq curl;do
which $libName>$DEVNULL|| usage
done
(テスト用)既存のPostgreSQLコンテナの削除
スクリプトのテスト用に作成したDBコンテナがあれば削除します(実際には既存のDBコンテナが立っているはずなので、この処理はコメントアウトされるでしょう)。docker ps -a
で、指定の名前のコンテナが存在するかを0
or1
で取得します。空白が入るためsed
で除去しています。
コンテナが存在した場合、停止と削除を実行します。
# remove existing containerexist=$(docker ps -a | grep$NAME | wc-l | sed's/ //g')if[[$exist= 1 ]];then
docker stop $NAME>$DEVNULL&& docker rm$NAME>$DEVNULLecho"existing container $NAME removed"fi
(テスト用)PostgreSQLコンテナの起動、疎通が確認できるまで待機
スクリプトのテスト用に、PostgreSQLのコンテナを起動します(実際には既にDBコンテナが立っているはずなので、この処理はコメントアウトされるでしょう)。
起動直後にpsql
を実行してしまうと接続できずにエラーとなるため、疎通が確認できるまで待つようにしています。
ここではpsql -c \l
を実行し、エラーが出力された場合はwhile
をループするようにしています。
function healthcheck(){PGPASSWORD=$PASSWORD psql -h$HOST-U$USER-c'\l'>$DEVNULL 2>&1 ||return 1
return 0
}# startup postgres
docker run -it-d-p$PORT:$PORT--name$NAME-ePOSTGRES_PASSWORD=$PASSWORD postgres:latest >$DEVNULL# wait for container running upwhile true;do
sleep 0.1 && healthcheck ||continue
break
done
(テスト用)データベース、テーブルの作成、レコードのinsertとselect
テスト用PostgreSQLコンテナ内にDB、Tableを作成し、レコードをinsert, selectします(実際には既存のDBコンテナが立っているはずなので、この処理はコメントアウトされるでしょう)。
# (temporary) preparation postgresPGPASSWORD=$PASSWORD psql -h$HOST-U$USER-c"create database $DB"PGPASSWORD=$PASSWORD psql -h$HOST-U$USER-d$DB<<EOF
create table fruit (id serial PRIMARY KEY, name text, price integer);
insert into fruit (name, price) values ('apple', 100), ('orange', 200), ('lemon', 300);
EOF
# select all records before updatesfor i in{1..3};do
PGPASSWORD=$PASSWORD psql -h$HOST-U$USER-d$DB<<EOF
select name, price from fruit where id = ${i};
EOF
done
HTTPリクエストで取得したResponseを元にSQLを実行
curl
でデータを取得します。ここではBitBankのPublic APIを利用しています。
取得したdata
はヒアドキュメント内で参照され、psql
が実行されます。
# fetch data by HTTP Request# following response should be returned# {# "success": 0,# "data": {# "code": 10000# }# }data=$(curl -s$URL | jq '.data | .code')echo$data# update record with the dataPGPASSWORD=$PASSWORD psql -h$HOST-U$USER-d$DB<<EOF
update fruit set price = ${data} where name = 'apple';
update fruit set price = ${data} where name = 'orange';
EOF
レコードが更新されたことを確認
取得したdata
によってレコードが更新されていることを確認します。
# select all records after updatesfor i in{1..3};do
PGPASSWORD=$PASSWORD psql -h$HOST-U$USER-d$DB<<EOF
select name, price from fruit where id = ${i};
EOF
done
スクリプト全体
上記をまとめると、以下となります。
実際には下記のコードをアレンジしてご使用頂くかと思います。
#!/bin/bashreadonly NAME='test_postgres'readonly PASSWORD='password'readonly HOST='0.0.0.0'readonly PORT='5432'readonly USER='postgres'readonly DB='temp'readonly DEVNULL='/dev/null'readonly URL='https://public.bitbank.cc'function healthcheck(){PGPASSWORD=$PASSWORD psql -h$HOST-U$USER-c'\l'>$DEVNULL 2>&1 ||return 1
return 0
}function usage(){echo"please install docker, psql, jq, and curl"exit 1
}# check requirementsfor libName in docker psql jq curl;do
which $libName>$DEVNULL|| usage
done# remove existing containerexist=$(docker ps -a | grep$NAME | wc-l | sed's/ //g')if[[$exist= 1 ]];then
docker stop $NAME>$DEVNULL&& docker rm$NAME>$DEVNULLecho"existing container $NAME removed"fi# startup postgres
docker run -it-d-p$PORT:$PORT--name$NAME-ePOSTGRES_PASSWORD=$PASSWORD postgres:latest >$DEVNULL# wait for container running upwhile true;do
sleep 0.1 && healthcheck ||continue
break
done# (temporary) preparation postgresPGPASSWORD=$PASSWORD psql -h$HOST-U$USER-c"create database $DB"PGPASSWORD=$PASSWORD psql -h$HOST-U$USER-d$DB<<EOF
create table fruit (id serial PRIMARY KEY, name text, price integer);
insert into fruit (name, price) values ('apple', 100), ('orange', 200), ('lemon', 300);
EOF
# select all records before updatesfor i in{1..3};do
PGPASSWORD=$PASSWORD psql -h$HOST-U$USER-d$DB<<EOF
select name, price from fruit where id = ${i};
EOF
done# fetch data by HTTP Request# following response should be returned# {# "success": 0,# "data": {# "code": 10000# }# }data=$(curl -s$URL | jq '.data | .code')echo$data# update record with the dataPGPASSWORD=$PASSWORD psql -h$HOST-U$USER-d$DB<<EOF
update fruit set price = ${data} where name = 'apple';
update fruit set price = ${data} where name = 'orange';
EOF
# select all records after updatesfor i in{1..3};do
PGPASSWORD=$PASSWORD psql -h$HOST-U$USER-d$DB<<EOF
select name, price from fruit where id = ${i};
EOF
done
さいごに
久々にシェルスクリプトを書いたのですが、楽しいですね。
こんな書き方があるよ、といったコメント等あれば是非お願いいたします。