タイポで本番事故が起きる理由|似た名前・全角・コピペと防ぎ方

1 文字の違いはエラーになるとは限りません。似た名前、全角、コピペ、履歴。タイポが静かに通ってしまう仕組みと、打ったものを確かめる習慣を説明します。

タイポが起きる原因と、打ったものを実行前に確かめる習慣を左右に並べた図
タイポが起きる原因と、打ったものを実行前に確かめる習慣を左右に並べた図

タイポ(打ち間違い)は、誰にでも起きる小さなミスです。開発環境なら、エラーが出て打ち直すだけで済みます。本番環境で怖いのは、タイポがエラーにならずに「別の正しいコマンド」として通ってしまう場合です。ベテランはタイポをしないのではなく、タイポが起きる前提で、打ったものを確かめる手順を持っています。この記事では、タイポが事故になる仕組みと、その場で真似できる確認の習慣を整理します。

タイポがエラーにならず通ってしまう仕組み

存在しないコマンドやファイル名を打てば、シェルは command not found や No such file or directory を返して止まります。この場合、被害はありません。危ないのは、打ち間違えた結果が「たまたま実在する別のもの」と一致したときです。コンピュータは意図を知らないので、正しい入力として実行します。

タイポの例実際に起きること
db-prd-01 のつもりで db-prod-01古い別名や別のサーバーに接続でき、そこで作業が完了したように見える
crontab -e のつもりで crontab -re と r はキーボードで隣り合い、-r は crontab を確認なしで全削除する
WHERE id = 1024 のつもりで 10421042 番の行が実在すれば、別の顧客のデータが書き換わる
> のつもりで >>、または逆> は既存ファイルを空にしてから書き込み、前の内容が消える
git push origin HEAD:feature/loignリモートに無いブランチ名でもエラーにならず、新しいブランチとして作られる

bash の変数名の打ち間違いも同じ種類の問題です。TARGET_DIR を TARGTE_DIR と打つと、未定義の変数は既定で空文字に展開され、エラーにはなりません。スクリプトの先頭に set -u を書くと、未定義の変数を使った時点でエラーとして止まります。

TARGET_DIR=/var/app/cacheecho "$TARGTE_DIR"      # 空行が出るだけでエラーにならないset -uecho "$TARGTE_DIR"      # bash: TARGTE_DIR: unbound variable
変数名のタイポを set -u で止める

タイポが起きやすい場面

似た名前と、手で打つ ID

本番と検証のホスト名は、prd と stg、01 と 02 のように数文字しか違わないことがよくあります。テーブル名も user と users、order_items と order_item のように、単数形と複数形の両方が存在することがあります。数字の 0 と英字の O、数字の 1 と英字の l は、フォントによっては見分けにくい組み合わせです。ID や伝票番号を画面から目で読んで手で打つと、桁の入れ替わりが起きやすくなります。

全角スペースや全角記号の混入

日本語入力をオンにしたままコマンドを打つと、全角スペースや全角のハイフン、引用符が混ざります。bash は全角スペースを区切りとして扱わないので、ls -l は「ls -l」という名前の 1 つのコマンドとして探され、見つからずにエラーになります。エラーになるうちはまだ安全で、SQL の文字列リテラルの中に全角文字が入った場合は構文としては正しいため、WHERE が 1 件も一致せず「0 件更新」で終わり、作業が済んだと誤解することがあります。

補完と履歴の呼び出し違い

Tab 補完は打ち間違いを減らしますが、候補が複数あるときは共通する部分までしか補完しません。releases と releases-old があるディレクトリで releases まで補完された状態から、残りを確かめずに Enter を押すと、意図と違う対象になることがあります。上矢印キーや Ctrl+R で過去のコマンドを呼び出す場合も、似たコマンドが履歴に複数あると、引数だけが違う古い行を選んでしまいます。

コピペで欠ける、混ざる

チャットや文書作成ソフトから貼り付けたコマンドは、引用符が “ ” のような装飾付きの文字に変わっていたり、-- が長いダッシュ 1 文字に置き換わっていたりすることがあります。範囲選択で先頭や末尾の 1 文字が欠けたり、前後の行まで一緒に選択したりすることもあります。改行を含む複数行を貼り付けると、端末の設定によっては貼り付けた瞬間に行ごと実行されます。

慣れによる読み飛ばしと、自分の文字は正しく見えること

毎日打つコマンドほど、指が先に動き、目は形だけを見て通り過ぎます。さらに、自分で打った文字列は、何を打とうとしたかを知っているため、実際の文字ではなく意図を読んでしまいがちです。文章の誤字を本人が見つけにくいのと同じ理由で、見直しを 1 回しても気づかないことがあります。ダブルチェックで別の人が読むのは、意図を知らない目で文字そのものを読むためです。

本番で特に危ない 5 つの場所

コマンドのすべての文字を同じ注意で読むのは現実的ではありません。ベテランは、1 文字違うと影響が大きい場所に絞って、文字単位で読みます。

場所1 文字違うと起きること読み方
ホスト名・DB 名本番と検証を取り違える接続後にプロンプトや hostname で確かめる
WHERE の値別の行を更新・削除する同じ条件の SELECT で対象の行を見る
パス別のディレクトリを消す・上書きする末尾のスラッシュと空白まで読む
リダイレクト先> で既存ファイルが空になる> と >> を区別し、出力先のファイル名を読む
ブランチ名新しいブランチができる・別のブランチに push するgit branch や git status で現在地を確かめる

パスでは、rsync の末尾のスラッシュが 1 文字で意味を変える例があります。rsync -a src/ dst/ は src の中身を dst に、rsync -a src dst/ は src というディレクトリごと dst の下にコピーします。--delete を付けている場合は、この違いで削除される範囲が変わります。

打ったものを確かめる習慣

Tab 補完を使い、補完結果を目で読む

長いパスやファイル名は手で打たず、Tab 補完を使います。補完は実在する名前しか出さないので、存在しない名前のタイポは防げます。ただし補完が止まった位置から先は自分で選ぶ必要があるため、Tab を 2 回押して候補を表示し、どれが選ばれたかを最後まで読んでから Enter を押します。

値は変数に入れて、echo で確かめる

同じホスト名や ID を何度も使う作業では、最初に変数へ入れて表示し、以後は変数を参照します。打つのが 1 回になるので、途中の行で打ち間違える機会が減ります。od -c で 1 バイトずつ表示すると、全角スペース(343 200 200)や制御文字など、画面では見分けにくい文字に気づけます。

HOST=db-prd-01ORDER_ID=1024printf '%s' "$HOST" | LC_ALL=C od -c   # 全角スペースなどが混ざっていないかmysql -h "$HOST" app -e "SELECT id, customer_name FROM orders WHERE id = $ORDER_ID;"
値を 1 回だけ打ち、表示して確かめてから使う

コピペした後は、貼り付けた内容を読む

ID やホスト名は、手で打つより元の画面からコピーするほうが確実です。ただし貼り付けた後に、先頭と末尾が欠けていないか、引用符やハイフンが変わっていないかを読みます。新しい bash(5.1 以降)や zsh では、貼り付けた文字列を Enter を押すまで実行しない bracketed paste が既定で有効です。手順書のコマンドは、ブラウザの装飾付き表示ではなく、プレーンテキストやコードブロックからコピーします。

プロンプトに環境を出し、読み上げる

ホスト名のタイポや窓の取り違えに気づくには、今いる環境が常に目に入る状態にします。本番サーバーではプロンプトにホスト名を出し、背景色を赤にするなど、検証環境と見た目を変えておきます。実行前には、ホスト名・対象・値を声に出して読み上げると、目で流し読みしていた箇所に気づきやすくなります。

PS1='\[\e[41;97m\][PRD \u@\h \W]\[\e[0m\]\$ '
本番サーバーの ~/.bashrc でプロンプトを赤くする例

--dry-run と SELECT で影響範囲を先に見る

多くのツールには、実際には変更せずに何が起きるかを表示する機能があります。タイポがあっても、表示された対象を見れば「思っていた件数・ファイルと違う」と気づけます。

rsync -a --delete --dry-run src/ dst/   # -n でも同じgit push --dry-run origin feature/logingit clean -n -dmake -n deploy
実行前に影響範囲を表示する

SQL では、UPDATE や DELETE と同じ WHERE で先に SELECT を実行し、返ってきた行の名前や件数が想定と合っているかを見ます。ID を打ち間違えていれば、別の顧客名が表示されるので、そこで止まれます。

既存ファイルを > で上書きしないようにする

bash で set -o noclobber を有効にすると、> で既存のファイルを上書きしようとしたときにエラーになります。意図して上書きするときは >| と書きます。>> と打つつもりで > を打つタイポへの保険になります。

チャットや手順書のタイポは、読んだ人の作業を誤らせる

タイポは自分の端末の中だけで起きるものではありません。手順書のホスト名が 1 文字違っていれば、それを読んだ人が正しく打つほど誤った場所で作業します。チャットで「stg で確認お願いします」と書くつもりが prd になっていれば、相手は本番を操作するかもしれません。書いた本人は意図を知っているので、読み返しても気づきにくいのは端末と同じです。

  • 手順書のホスト名・DB 名・ブランチ名は、実際の画面や設定からコピーして書く。
  • 環境名(本番・検証)は略語だけにせず、「本番(prd)」のように日本語でも併記する。
  • 誤りに気づいたら、「訂正:」として誤った値と正しい値の両方を書き、元の投稿も直す。
  • 誤った値ですでに作業した人がいる可能性があれば、その戻し方まで書き添える。

「typo」や「*login」のような短い訂正だけでは、どこがどう違ったのかを読む人が推測しなければなりません。正しい値をそのままコピーできる形で書くことが、訂正のいちばんの目的です。

タイポを事故にしないためのチェックリスト

  • ホスト名・DB 名は、接続後のプロンプトや hostname、\conninfo で確かめたか。
  • ID・ホスト名は手で打たずにコピーし、貼り付けた内容を読み直したか。
  • 日本語入力がオフになっていて、全角スペースや全角記号が混ざっていないか。
  • Tab 補完や履歴で呼び出したコマンドの引数を、最後まで読んだか。
  • UPDATE・DELETE の前に、同じ WHERE の SELECT で対象の行を見たか。
  • --dry-run など、変更せずに影響範囲を表示する方法を先に使ったか。
  • 手順書やチャットに書いた値を、送る前に元の画面と突き合わせたか。

タイポは注意力だけでは無くせません。打つ回数を減らし、打ったものを実行前に表示して読む手順にしておけば、1 文字の違いは事故になる前に見つかります。下の問題で、1 文字の違いを見抜けるか確かめてみてください。

問題で確かめる

この記事の内容を、制限時間つきの問題で確かめられます。

参考

よくある質問

タイポはなぜ自分では気づきにくいのですか?

自分で打った文字列は、何を打とうとしたかを知っているため、実際の文字ではなく意図を読んでしまいがちです。見直しを 1 回しても気づかないことがあるので、別の人に読んでもらうか、表示して確かめる手順を入れます。

全角スペースがコマンドに混ざるとどうなりますか?

bash は全角スペースを引数の区切りとして扱わないため、前後の文字とつながった 1 つの語として解釈され、多くはエラーになります。SQL の文字列の中に入った場合は構文として正しいため、一致する行が 0 件になるだけで気づきにくくなります。

Tab 補完を使えばタイポは防げますか?

補完は実在する名前しか出さないため、存在しない名前のタイポは防げます。ただし似た名前が複数あるときは共通部分までしか補完されないので、補完後の文字列を最後まで読んでから Enter を押す必要があります。

bash で変数名を打ち間違えるとどうなりますか?

既定では、未定義の変数は空文字に展開され、エラーになりません。パスの一部に使っていると、意図と違う場所が対象になります。スクリプトの先頭に set -u を書くと、未定義の変数を使った時点で止まります。

手順書やチャットのタイポに気づいたらどう訂正しますか?

「訂正:」として誤った値と正しい値を両方書き、元の投稿や手順書も直します。誤った値ですでに作業した人がいる可能性があれば、その戻し方も書き添えます。