MySQLでレプリケーションを設定する

レプリケーションMySQLで最も重要な機能の一つで、その用途は多岐に渡ります。それゆえ素早くセットアップできることが好ましいです。ここではその手順をまとめておきます。

方法はいくつかありますがここではマスターからmysqldumpでデータを取ってくる方法を使います。

1. マスターサーバーのコンフィギュレーション

マスターでは以下のようにオプションを設定します。

[mysqld]
bind-address = 10.132.0.2
server_id = 1
log_bin = /var/log/mysql/mysql-bin.log
sync_binlog = 1

server_idレプリケーションするグループ内で一意である必要があります。デフォルトが1なので他のインスタンスと衝突しないように違う値を割り当てるのが安全ですがここではデフォルトのままにしておきます。今回はローカルネットワーク内にマスター・レプリカを立てるのでbind-addressにはローカルIPを書いておきます。log_binにはバイナリログの位置を指定、sync_binlogフラグを立てることでトランザクション毎にバイナリログが同期することを保証します。

2. マスターにレプリケーションユーザーを作成する

レプリケーションではマスターがサーバーでレプリカがクライアントの役割を果たします。よってマスター側にレプリカがアクセスする用のユーザーを作成します。

GRANT REPLICATION SLAVE ON *.* TO 'slave_user'@'%' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;

ここではクライアントホストに%を指定することで複数のレプリカでユーザーを使い回す想定で作成します。

3. マスターのデータをmysqldumpで取得する

バックアップをとる方法でまとめたのと同様にmysqldumpコマンドによりデータの論理バックアップを取得します。

$ sudo mysqldump --all-databases --master-data=2 --single-transaction --flush-logs > backup/dumpfile.sql

--all-databasesにより全てのデータベースを対象にし、--master-data=2によりダンプデータにレプリケーションの開始位置を書き込ませます。--single-transactionは複数データベースのデータを取得する際の不整合を防ぐオプション(InnoDB専用)、--flush-logsによりバイナリログのローテートを指示します。

4. スレーブのコンフィギュレーション

スレーブのmysql.confファイルを以下のように設定します。

[mysqld]
bind-address = 10.132.0.3
server-id = 2
relay-log = /var/log/mysql/mysql-relay-bin.log

スレーブはserver-idに2を割り当て、ローカルIPの設定もします。マスターから取得するバイナリログはまずリレーログという領域に置かれます。その後マスター接続するのとは別のスレッドがリレーログの内容をデータに書き込みます。relay-logの値にリレーログを書き込む場所を指定しておきます。

5. ダンプしたデータのリストア

先ほどマスターから取得したダンプファイルをスレーブに適用します。

$ sudo mysql < dumpfile.sql

6. スレーブでレプリケーションの設定をする

スレーブでマスターとバイナリログ上のレプリケーションの開始位置を指定します。レプリケーションの開始位置は以下のようにダンプデータから取得できます。

$ cat dumpfile.sql | head -n30 | grep CHANGE
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=154;

mysqlに以下のクエリを流します。

CHANGE MASTER TO
    MASTER_HOST='10.132.0.2',
    MASTER_USER='slave_user',
    MASTER_PASSWORD='password',
    MASTER_PORT=3306,
    MASTER_LOG_FILE='mysql-bin.000002',
    MASTER_LOG_POS=154,
    MASTER_CONNECT_RETRY=10;

7. マスターに更新クエリをかける

レプリケーションがうまくいってることを確認するためにマスターのデータを更新してみましょう。

8. レプリケーションの開始

スレーブ側でレプリケーションを開始します。

START SLAVE;

9. レプリケーションの確認

スレーブ側では以下のように確認します。

SHOW SLAVE STATUS\G

またマスター側での確認は

SHOW MASTER STATUS;
SHOW SLAVE HOSTS;

です。

先ほどマスターで更新したデータがスレーブに書き込まれていること、マスターへの更新クエリがスレーブに反映されることも確認しましょう。

参考

MySQLで差分バックアップをとる

リストア処理においてフルバックアップと合わせて必要になるのが差分バックアップです。ということで備忘録。

1. バイナリログを記録する

まずはこれをしないと始まりません。設定ファイルのlog-binの項目をコメントインし、サーバーを再起動しておきましょう。

2. フルバックアップをとる

--flush-logsオプションをつけてログをローテートしておきます。こうしておくとリストア時にファイルの先頭から復元すればよいため手順がシンプルになります。

$ sudo mysqldump --flush-logs --lock-all-tables --all-databases > backup/full-$(date +%Y%m%d).sql

3. バイナリログを保存しておく

$ sudo mysqlbinlog /var/log/mysql/mysql-bin.000005 > binlog/diff-$(date +%H%M%S).sql

これで保存した分まで復元できるので常に最新のものを安全な場所に保管できるようにしておきましょう。

バックアップの処理はここまでで以降リストアの処理です。緊張感が欲しい方はDROP DATABASEしましょう。

4. フルバックアップを復元する

$ sudo mysql < backup/full-20181030.sql

フルバックアップ取得時まで復元しました。次にバイナリログ分を適用します。

5. バイナリログの適用

フルバックアップと同じようにmysqlコマンドに流すだけです。

$ sudo mysql < binlog/diff-193632.sql

これで完了です。

ログをローテートしたくないとき

バックアップ時に--master-data=2オプションをつけましょう。こうすることでダンプデータにどのバイナリログのどの位置からリストアすればいいかがわかります。

sudo mysqldump --lock-all-tables --all-databases --master-data=2 > backup/full-$(date +%Y%m%d).sql
$ head -n30 backup/full-20181030.sql | grep 'CHANGE MASTER'
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000005', MASTER_LOG_POS=831724;

位置を指定してリストアする

mysqlbinlog時に--start-positionを指定して展開します。

$ sudo mysqlbinlog --start-position=831724 /var/log/mysql/mysql-bin.000005 > binlog/diff-$(date +%H%M%S).sql

あとは同じリストア手順。(ということはバイナリログはmysqlbinlogを通さずそのまま保管したほうがいいのか......。)

参考

mysqldumpでフルバックアップとリストア

MySQLのバックアップにはいくつか方法があります。その中でも最もオーソドックスな方法であるmysqldumpを使った方法についてまとめておきます。

mysqldumpを使った方法の特徴としては

  • 手軽である
  • 無停止でバックアップが取れる(オンラインバックアップ)
  • データのダンプを出力する(論理バックアップ)
  • リストアに時間がかかる

などがあります。

1. セットアップ

こちらの記事にしたがってMySQLサーバーを用意します。

2. ダンプの取得

以下のようにmysqldumpコマンドを使いダンプデータを取得します。

$ sudo mysqldump example > backup/backup-$(date +%Y%m%d).sql

以上です。簡単。

リストア

リストアのためDROP TABLEしておきます。

リストアの際には先ほどのダンプデータをリダイレクトで入力するだけ。

$ sudo mysql example < backup/backup-20181029.sql

リストアも簡単。

全てのデータベースをバックアップしたい

--all-databasesオプションを使います。

$ sudo mysqldump --all-databases > backup/backup-$(date +%Y%m%d).sql

これならDROP DATABASEした状態でも以下でリストア可能。

$ sudo mysql < backup/backup-20181029.sql

バックアップを圧縮して取りたい

gzipにパイプすれば圧縮も簡単。

$ sudo mysqldump --all-databases | gzip > backup/backup-$(date +%Y%m%d).sql.gz

リストアもgunzip経由で。

$ gunzip < backup/backup-20181029.sql.gz | sudo mysql

cronで定期的にバックアップしたい

最後にcronの設定をしてみます。MySQL接続のため.my.cnfは事前に設定しておきましょう。 例えば毎日午前3時にバックアップを取りたかったらcrontab -eに以下を追加します。

0 3 * * * /usr/bin/mysqldump -u root --all-databases > /path/to/home/backup/full-$(date +\%Y\%m\%d).sql

参考

MySQLサーバーの設置

チュートリアルなどでMySQLサーバーが欲しいことがよくあるので手順をまとめておきます。OSはUbuntu18.04TLSです。

【参考】

1. インスタンスの作成

自分の環境に合わせてインスタンスをセットアップします。今回はGCP上に設置します。

$ gcloud compute instances create mysql-example3 --machine-type=f1-micro --image=ubuntu-1804-bionic-v20181029 --image-project=ubuntu-os-cloud
Created [https://www.googleapis.com/compute/v1/projects/playground-192621/zones/europe-west1-b/instances/mysql-example3].
NAME            ZONE            MACHINE_TYPE  PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP     STATUS
mysql-example3  europe-west1-b  f1-micro                   10.132.0.5   35.205.118.215  RUNNING

2. 作成したインスタンスSSHする

$ gcloud computh ssh mysql-example3

3. mysqlのダウンロード

$ sudo apt-get update && sudo apt-get install -y mysql-server

これだけ。一応ps aux | grep mysqlで確認しておきます。

4. .my.cnfの設置

便利のためにホームディレクトリに.my.cnfファイルを設置しておきます。中身はこんな感じ(userとpassは適宜変えてね)。

[client]
user = root
password = 

5. ダミーデータの作成と導入

ここのサイトでダミーのデータを簡単に作れます。

6. .sqlファイルを作成したらインスタンスに送る。

$ gcloud compute scp data.sql mysql-example3:~

7. データベースの作成

$ sudo mysql -e 'create database example;'

7. リダイレクトでmysqlコマンドに繋ぐ

$ sudo mysql -- example < data.sql

ここまで5分でできるようになろう。

【メモ】AWKについて

AWKについて調べた際のメモおよび「『シェル芸』に効くAWK処方箋」の読書メモです。

  • マニュアルはここ(あとで読む)
  • 【 awk 】コマンド(基本編)――テキストの加工とパターン処理を行う
    • awk ‘pattern {action}’ filename
    • $番号でフィールドを指定
    • スクリプトをファイルに保存して実行することもできる
    • 入力の一行目を削除したい場合はパイプラインの前段にsed 1dを通しておく
    • いくつか組み込み変数がある
    • デフォルトで拡張正規表現でパターンの位置に/pattern/で記述する
    • &&||で条件をつなぐことができる
    • ~はマッチ演算子で例えば$4 ~ /pattern/というようにどのフィールドのマッチングをとるか指定できる
    • BEGIN { … }で全行処理前のアクション、END { … }で全行処理後のアクションを記述できる
    • アクション内では複数の処理を実行してもいい
    • shebang#! /usr/bin/awk -f
    • 一行単位の処理では不可能な条件分岐は制御構文を使う
    • if, switch ~ case, while, do ~ while, forなど一通り使える
    • いくつかの組み込み関数が使える
  • [初心者向け]Awkの使い方
  • AWKのまとめ
    • 関数定義はfunction name(args) { … }で記述できる
  • AWK リファレンス
    • 独立したスクリプト言語なのでawkスクリプト/インタプリタというのが正確
    • 複数のパターン・アクションが指定された場合、入力の行ごとに上から順に評価・実行される
      • next構文を使うと以下のパターン・アクションを無視して次の行にいける(for分のcontinue的役割)
      • そのほかnextfilereturnexitもある
    • —assign var=“value”awkスクリプトに変数を渡すことができる
    • あるいはスクリプト内から$変数名で直接シェル変数を参照してもいい
    • 正規表現に変数を使いたい場合はmatch関数を使う
  • AWK - wikipedia
    • もともとはテキスト処理プログラムとして開発された
    • プリミティブ型は数値と文字列のみ
    • 変数は関数の引数を除いてはグローバルスコープを持つ
      • 関数の引数を余分に定義してローカル変数とするきな臭いプラクティスがある
  • awk とはどんな言語か
  • AWKコマンドの使い方
    • getline関数で次の行を取得できる
  • 実例でわかる awk: 第 1 回
    • 区切り文字は-Fオプションで指定
    • スクリプトで実行する場合は区切り文字を(オプションではなく)スクリプト内で設定するのがよい
    • 変数に数値を文字列として代入しても算術演算が適用される
  • はじめてのAWK
    • 配列はA[2,4,6,8]で表現できる
    • grepawkで書いたコードがあるのであとで読む
  • Getting Started with awk
  • なるべく書かないawkの使い方
    • awkスクリプトとは 'パターン{アクション}' の集合”
    • cutとの違いは単純に使いやすさの問題
      • デフォルトの区切り文字が一文字以上の空白であったりするところ
    • awkとは、表計算コマンドなのかもしれない。”
    • 組み込み変数は7つ
  • 実用 awk ワンライナー
    • awkAWKの処理系のことを指しており、別物なので注意
    • パターンをカンマで区切ると”その範囲内はマッチする”という動作になる
    • レシピ集になっているので必見
  • 「シェル芸」に効くAWK処方箋
    • 第1章:導入
      • シェル芸:ワンライナーで文字列加工すること
      • パターンは条件式そのもの
      • 比較・マッチング演算子の返り値は数字の0または1
      • 代入の戻り値は左辺値
      • 戻り値が0の場合でも数値を表示したいときはダブルクオートをつけて文字列として処理させる
    • 第2章:行操作
      • AWKでtailを作りたいときはtacを使った方がいい
      • カンマは範囲指定演算子と呼ばれ、スイッチのような働きをする
      • カンマの後半を偽な値にすることで、マッチした行以降という表現になる
    • 第3章:列操作
      • AWKとcutの最大の違いは区切り文字に正規表現が使えるかどうか
      • コマンドラインで組み込み変数を指定するときは-vオプションを使う
      • OFSで期待通りに出力するには$1 = $1でレコードの再構築をする必要がある
    • 第4章:文字列関数
      • AWKのインデックスは1から始まるので注意
      • substr関数とindex関数の組み合わせで文字列を抜き出す
      • match関数は組み込み変数に結果を代入するので後から参照できる
        • grep -oと等価なので文字数の少ないそっちがおすすめ
      • sub/gsubの返り値は置換した個数であり置換結果ではないので注意
    • 第5章:数値演算
      • 数字は全て倍精度不動少数点数扱い
    • 第6章:配列・連想配列
      • 配列はインデックスが数値、連想配列は文字列なだけで同じデータ構造
      • for i in arrayでループ処理できるがiに入るのは値ではなくインデックス
      • split関数で手軽に配列を作成できる
      • if “key” in arrayで配列の検査ができる
    • 第7章:GNU AWK拡張機能
      • match関数の第3引数でマッチした値を参照できる
    • 第8章:パイプ
      • かつてsrandを使って時刻を取得するという裏技があった
      • gensub関数を使えば置換後の文字列を返り値として取得できる。後方参照もできる
      • 双方向パイプを使ってAWK内で他のコマンドの実行、値の受け渡しができる
      • (xargsの本質は列の行への変換)
      • 双方向パイプでソケットに直接書き込むことでインターネット通信すらできる
        • まあ、curl/wgetを使おうね……
    • 第9章:GNU拡張とCSVファイルの扱い
      • フィールドの中のパターンを指定するFPAT変数を使うことでカンマをフィールドに含むCSVも簡単に扱える
      • gawkは多次元配列を正式にサポートする
      • BEGINFILE部によりファイルが存在するかを確認できる
      • @変数()で変数を関数として呼び出す
    • 第10章:もっとGNU拡張
      • MPFRによる浮動小数点数演算の精度向上
      • @loadによりライブラリ・ファイルの読み込みができる
      • fork関数でforkシステムコールを呼び出せる
      • in-placeオプションでファイルの更新ができる
    • 第11章:実践
      • コマンドをAWKで書き換えていくという方法がある
      • さらに応用としてサーバを立てたり、CMSを作ることもできる
    • 第12章:Podcastダイジェスト

まとめ

  • awkAWKという処理系の実装であり両者は別物
  • awk ‘pattern {action}’ [filename]、特にパターン・アクションの組み合わせの集合が全て
  • 独立したスクリプト言語なのでサーバプログラムも作れる

とりあえずなんとか読むことはできるはず。書けるようになるのはまた今度頑張る。

【読了】新しいシェルプログラミングの教科書

一介のソフトウェアエンジニアとしてシェルスクリプトくらいさらさらと書けますよね?......僕は書けません。というわけで「新しいシェルプログラミングの教科書」を読んだのでその際のメモです。

www.amazon.co.jp

  • Chapter01: シェルとは
    • ログインシェルの確認は$ cat /etc/shells
    • 新しいシェルの起動は$ bash、終了は$ exit
    • シェル=コマンドインタプリタ
    • 「どれだけ便利にコマンドを実行するか」
    • コマンドインタプリタの機能をカーネルから取り出したもの → 「1つのことをうまくやらせる」
    • コマンド実行はforkし、子プロセス上でexecする
  • Chapter02: シェルスクリプトとは
    • シェルスクリプトを書く = シェルでプログラミングする
    • コマンドを組み合わせて新しいコマンドをつくる
    • シェルスクリプトのメリット
      • 再利用性
      • typoの防止
    • デメリット
    • 利用例
      • 新たなコマンドの作成
        • コマンドが実行可能フィアルなのかシェルスクリプトなのかはfileコマンドで確認できる
  • Chapter03: 基本
    • 改行=エンターキー = 実行
    • 複数行に書きたいときは\
    • 一つの行にまとめたいときは;
    • 複数行コメントは存在しない
    • bashコマンドは引数をスクリプトとして読み込んで実行→実行権限がいらない
      • スクリプトがどのシェルで書かれているかを知っていないといけない
      • ./scriptはいつでも有効だが、bash scriptはscriptが例えばバイナリだと動かない
  • Chapter04: 変数
    • 値は文字列として解釈される
    • $をつけて参照
    • 明示的に参照するときは${}で囲む
      • 変数のすぐ後ろに入力がある時使える
    • 環境変数 = コマンドに引き継がれる変数
      • コマンドから参照できるかどうか
      • exportで変数を環境変数にする
      • 慣例として変数名を大文字にする
    • $1, $2, $3 … でスクリプトに渡された引数を参照できる
      • $*, $@で全てを一度に参照できる
      • 通常は$@で参照
    • IFSは区切り文字を表し、参照する際はecho "$IFS" | od -aとする
    • 特殊パラメータ
      • $# ... 引数の個数
      • $? ... 前回コマンドの終了ステータス
      • $$でプロセスIDを取得、tmpのファイル名などに利用
    • declareコマンドで変数の型を宣言できる
      • 整数型の場合代入の右辺は算術評価される
    • 配列の宣言はvar=(a b c)、要素の参照は${var[i]}、追加はvar+=(value1 value2)、削除はunset var[i]、要素数の取得は${#var[@]}
    • 連想配列を作る際はdeclare -Aで明示する必要がある
  • Chapter05: 展開・クオーティング
    • 展開の種類 ... パス名展開、ブレース展開、チルダ展開、パラメータ展開、コマンド置換、算術評価・展開、プロセス置換、履歴展開
    • パス名展開
      • マッチするファイルが存在する場合のみ有効
      • 正規表現とまた違うマッチング規則なので注意
      • ドットで始まるファイルを展開したいときは明示する必要がある
    • ブレース展開
      • マッチするファイルがなくてもいい
        • 新しいファイルを作るときなどに利用
    • チルダ展開
    • パラメタ展開
      • $varとか${var}とかのこと
      • ${name:-value} ... デフォルト値の指定
      • ${name:=value} ... デフォルト値を代入して返す
      • ${name:?value} ... 値がない時のエラーメッセージの指定
      • それぞれ:を除くと値が未設定の時のみの動作になり、空文字のときは空文字がそのまま返る
      • ${name:index:length}で文字列のスライシングができる
      • ${#name} ... 文字数が返る
      • ${name#pattern} ... 先頭から最短マッチでpatternを切り落とす
        • ファイル名の取得 ${path##*/}
      • ${name%pattern} ... 末尾から最短マッチでpatternを切り落とす
      • それぞれ記号を二つ重ねると最長マッチになる
      • ${name/pattern/substring} ... マッチするパターンを置換して返す
        • 使い所不明
    • コマンド置換
      • $()と``は等価
    • 算術評価・展開
      • ((算術式)) ... 終了ステータスが返る
      • $((算術式)) ... 評価結果が返る
      • exprコマンドでもいいけどこっちの方が早い
      • letも等価だが、読みやすさを考えると代入のみに使うのがおすすめ
    • プロセス置換
      • <()で標準入力が二つ欲しい時にパイプラインの代わりとして使える
      • (パイプラインの本質は一時ファイルなんだなー...。)
    • 履歴展開
      • !から始まる入力でコマンドの実行履歴を参照できる
      • スクリプトで使うことはまずない
    • クオーティングで特殊文字を無効化する
      • \特殊文字エスケープ
      • ''で全ての展開のエスケープ
      • ""は特殊文字を一部だけ無効化する
        • 「パラメタ展開」「コマンド置換」「算術展開」
  • Chapter06: 制御構造
    • 条件分岐
      • if (条件); then ~ elif ~ else ~ fi
      • 条件はコマンドとして実行され、終了ステータスが0のとき真、0以外のとき偽に評価される
      • []はtestという"コマンド"
      • :はヌルコマンドといい、必ず正常終了する
      • command1 && command2 ... command1の終了ステータスが0のときのみcommand2を実行する
      • command1 || command2 ... command1の終了ステータスが0以外のときのみcommand2を実行する
      • []に対して[[]]を使う最大のモチベーションは"読みやすさ"
        • [[]]はコマンドではなく構文
        • パターンマッチも使える
    • ループ
      • for (変数) in (単語リスト) do ~ done
        • break、continueが使える
      • case (文字列) in (パターン1) ~ ;; (パターン2) ~ ;; ... esac
        • *)でデフォルト句を表す
      • whileとその逆のuntilもあるよ
  • Chapter07: リダイレクト・パイプ
    • 標準入出力がファイルだからリダイレクト(元|先)つまり標準入出力の切り替え先もファイルだよ
    • (ファイルディスクリプタ番号)> (接続先ファイル)が基本形
    • &(ファイルディスクリプタ番号)で他の接続先を指定できる
      • 標準出力にエラー出力を繋ぐ2>&1は定型文
    • 出力を捨てるときは/dev/nullを接続先に指定
      • 標準出力を捨てるのはifの条件部など
      • 標準エラーを捨てるのはエラーを無視する時
      • 両方捨てる決まり文句は> /dev/null 2>&1
    • >で上書き、>>で追記
    • (コマンド) <<< (終了文字列) ~ (終了文字列)でヒアドクが書ける
      • 終了文字列をクオーティングすることでクオーティングのルールを適用できる
    • パイプラインは一時ファイルが本質
    • {}()で複数コマンドのグループ化ができる
      • 複数コマンドの出力をまとめて出力したいときとか
      • {}は同一プロセス内、()はサブシェル内で実行される→変数を参照する時注意
  • Chapter08: 関数
    • 三通りの書き方の中で(関数名)() { ~ }が一般的
    • ローカルスコープで変数を宣言したいときは必ずlocalを使う
    • 引数の参照は同様に位置パラメータを使う
    • returnで終了ステータスを明示的に返すことができる
  • Chapter09: 組み込みコマンド
    • :
      • 無限ループが作れる
    • printf
      • printf '%s\n' "~"をよく使う
    • command, builtin
      • commandは組み込みコマンドと実行可能ファイル、builtinは組み込みコマンドから探す
    • type
      • コマンドの種別を調べたい時
    • shift
      • 解析済みの位置パラメータを削除するとき
      • オプションの解析とかで意外とよく使う
    • set
      • 目的が複数あるという意味で一番UNIXらしくないコマンド
      • 1)シェルのオプションの表示・変更、2)位置パラメータの設定
    • unset
      • 変数を削除したい時
    • read
      • 標準入力から一行取り出すとき
      • ループのリスト部によく使う例えばwhile IFS= read -r line do ~ done
        • 入力行がlineに代入される、変数名を複数指定したときはIFS区切りでそれぞれ代入される
    • trap
      • 指定したシグナルを補足して指定の処理をする
      • 終了前の後処理を記述したいときとか
    • wait
      • バックグラウンドで実行した処理の終了を待ちたいとき
    • exec
      • 現在のシェルをコマンドのプロセスに差し替えたいとき
      • 現在のシェルのリダイレクト先を変更するときにも使う
    • eval
      • コマンドを動的に組み立てて実行したいとき
      • 実行シェルの環境変数も設定したいスクリプト、具体例はssh-agent
  • Chapter10: 正規表現・文字列操作
    • grep, sedそれからawkも不自由なく使えるようになろうね
    • grepはパターンの検索、sedは置換に使う
  • Chapter11: シェルスクリプトの実行
    • shebangはexecシステムコールの仕様
      • ファイルの先頭2バイトが#!だった時に内容を(バイナリではなく)テキストファイルとして解析する
      • #!以降をコマンドとしてファイル名を引数に実行する
        • → 実行コマンドをスクリプト内に記述できる = 呼び出し側はどのコマンドかを気にせずただ実行するだけでいい
    • sourceは引数ファイルを現在のシェル内で実行する
      • 変数など環境のセットアップを一つのファイルにまとめておける
  • Chapter12: 具体例
  • Chapter13: シェル補完の書き方とか
  • Chapter14: テスト・デバッグ
    • 静的解析
      • noexecオプション ... 構文チェック
      • ShellCheck ... Webサイトおよびコマンドラインツール
    • Batsというツールでテストスクリプトが書ける
    • デバッグ
      • シェルオプション
        • verbose ... 実行するコマンドラインの出力
        • xtrace ... 各種展開の結果を出力
        • nounset ... 未定義変数参照時にエラーとともにexitする
        • errexit ... 終了ステータスが0以外のコマンドを実行した直後にexitする
    • パイプラインで繋いだ後ろはサブシェルなので変数を参照できない点に注意

まとめ

「新しいLinuxの教科書」が読みやすかったので期待しましたが期待通りでした。シェルスクリプトを学ぼうという方には非常におすすめです。文法がわかったのでどんどん書いて身につけていこうというところですが実務ではあんまり使わないのでどうしたものか......。

7~9月振り返り

久し振りになってしまいました。

やったこと

今回はテーマが月ごとに1つずつありました。それぞれ7月テスト/TDD・8月オブジェクト指向・9月セキュリティです。このテーマで勉強を始めるにあたって結構な不安がありました。それは設計という正解のないテーマに対して、成長を実感できるか、本を読んだだけで何も変化を感じずモヤモヤして終わるのではないかというものです。結論から言うと心配していたことは全く起こりませんでした。つまり、3ヶ月前の自分と比べて今書いているコードが段違いにきれいになっていることを実感しています。具体的にどうしているかは別の機会に紹介したいと思いますが、TDDを積極的に取り入れています。主なメリットは 1) 仕様漏れを実装前に発見できる 2) 内部実装を知る前にあるべきインターフェイスを検討できる 3) テストさえ通れば中身がどうあれ動くことを確認できるなどです。また今年の頭に読んだもののモヤモヤしていたパターンという分野があります。そのモヤモヤへの答えはケントベックのTDD入門にありました。これまで"良い設計"が実装されるものだとずっと思い込んでいたのですが「設計と実装は互いにフィードバックする」というきれいなコードを書く人にとっておそらく常識といえる考え方に出会えたのはこの三ヶ月で最も価値のあることでした。パターンとの付き合い方がわかったことで本に書かれていることと実際とのギャップが埋まった感覚があります。

セキュリティに関してはテーマは非常に面白かったものの時間不足でした。せめてCTFに参加してみたかったです。

良かった点・反省点・改善点

  • ✅いっぱい読んだ
    • オブジェクト指向に関わる有名な本は一通り触れることができたと思います。おそらくこの分野の本であればどんな本でもすっと読めるだけのバックグラウンドが揃ったのではないでしょうか。
  • ✅即実践
    • 仕事にダイレクトに活かせる分野だったのでフィードバックが早く、学んだことを効率よく身につけることができました。
  • ❌本しか読んでない
    • インプットのチャンネルを増やしたいと思う次第です。
  • ❌学習のプランが大雑把だった
    • 目標を設定するのが難しかったし、前提の知識が少なかったため想像しにくい部分もありましたが、やはり目標があってこそ効率的に学習できるので、プランニングの時間をしっかりとるべきでした。
  • ❌アウトプットできなかった
    • 正解のないテーマに対してどの角度で切り込んでいけば、本に書いていることをただ紹介するだけではない切り口を見いだせるのかずっと考えていたものの結局思いつくことができませんでした。この先もコードを書く以上常に向き合っていくテーマなのでいつか自分の言葉で語れればと思います。
    • それと同時にアウトプットを仕組化する必要を感じています。

この三ヶ月は旅行に熱心になっていて、勉強が途切れ途切れになってしまったのがやや寂しくもあります。今年残り三ヶ月も頑張っていきます。