Bash の AND 演算子、 OR 演算子での条件判定の実行順序で勘違いしていたこと
2015.06.29
こんにちは、野口です。
Bash でちょっとはまったことがありましたので、メモを兼ねて共有です。
Linux サーバに SSH の公開鍵を登録するときに、 .ssh
ディレクトリがそもそも掘られていなかったり、
authorized_keys
あたりのパーミッション調整等、数コマンドですが、いろいろチェックしてやることがあります。
毎度毎度同じことをやっているなと思い、ワンライナーでできないか考えて以下のようなシェルスクリプトを書きました。
([ ! -e ~/.ssh ] && mkdir ~/.ssh && chmod 700 ~/.ssh ) || cat <<EOF >>~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys ssh-rsa blahblahblah rsa-key-20150608-comment EOF
これはうまくいくときもありますが、うまくいかないときもあります。
正しくはこうです。
([ ! -e ~/.ssh ] && mkdir ~/.ssh && chmod 700 ~/.ssh ) ; cat <<EOF >>~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys ssh-rsa blahblahblah rsa-key-20150608-comment EOF
何が違うかお分かりでしょうか?
後者の例では ||
演算子を使うのではなく、 ;
で次のコマンドに制御が移るようにしています。
前者の例では ( )
内の実行結果が真の場合は後ろのコマンドは評価されません。
つまり、 .ssh
ディレクトリがなかったら作成されますが、 cat コマンドでファイルを生成している部分は実行されず、後ろの chmod コマンド実行に引き継がれてファイルが存在しない旨のエラーとなります。
によれば以下のように説明されています。
OR リストは
[ command1 || command2 ]
という形式であり、 command1 が 0 以外の終了ステータスを返した場合に限り command2 が実行されます。
前者の例では前の実行結果の真偽にかかわらず後ろのコマンドも実行されると予期していたのですが、
前のコマンドの実行結果が真偽にかかわらず後ろのコマンドを実行したい場合は複数のコマンドをつなげる ;
を使えばいいのです。
一般的なプログラミング言語でも同じことが言えます。
OR 演算子で繋げられた条件文は前文の式の評価結果が真なら後ろの条件式の評価は省略されます。
後ろの条件式の評価のコストが無駄だからです。
シェルスクリプトを覚えていくと意外といい頭の体操になるなと感じた一例でした。
CONTACT
お問い合わせ
あなたの「想い」に挑戦します。
どうぞお気軽にお問い合わせください。
受付時間:平日9:00〜18:00 日・祝日・弊社指定休業日は除く