rpmbuildのspecファイル内スクリプトをエラーの終了コードで止めない

2019年11月25日月曜日

Linux

t f B! P L
rpmbuildで自作のパッケージを作っている時、「インストール前にcronが設定されているかどうか確認して、設定されていれば設定をクリアする」という処理が必要になりました。そこでrpmのspecファイルに書いたのが、次のようなスクリプトです。

%pre
echo "stop cron"
crontab -u taro -l && crontab -u taro -r

ユーザーtaroのcronが設定済みであれば、-rオプションでcronの設定をクリアするというコードです。しかし、このコードは意図通りには動作しません。taroのcronが設定済みであればよいのですが、設定されていなかった場合、"crontab -u taro -l"の部分が返す終了コード1によって、rpmのインストール自体が終了してしまいます。

tarのspecファイルを参考にしてみる

tarコマンドのspecファイルを見てみると、コマンドの最後に|| :が付けられているので、これを参考にspecファイルを修正すると、意図通りに動作するようになりました。

:(コロン)の意味がわからない

スクリプト中の&&は「前のコマンドが成功したら(終了コードが0だったら)後続するコマンドを実行する」という意味で、||は 「前のコマンドが0以外の終了コードだったら、後続するコマンドを実行する」という意味であることは、すぐに分かったのですが、最後の:の意味が良くわかりませんでした。
これはbashのマニュアル(man bash)に説明がありました。:は、常に終了コード0を返すビルドインコマンドでした。
SHELL BUILTIN COMMANDS
: [arguments] No effect; the command does nothing beyond expanding arguments and performing any specified redirec‐ tions. A zero exit code is returned.

先ほどのコードの最後に"::|"を付加すると、意図通りに動作するようになりました。

%pre
echo "stop cron"
crontab -u taro -l && crontab -u taro -r || :

||:が最後にあると、終了コードが0になるので、コマンドの終了コードが0以外であってもrpmが途中終了することなく意図通りに動作するという仕組みのようです。

bashも同じらしいが

rpmのspecファイルではありませんが、bashのマニュアルによると、シェルスクリプトのshebangが#!/bin/shの場合は 、shと同じ動作になるらしいです。
If bash is invoked with the name sh, it tries to mimic the startup behavior of historical versions of sh asclosely as possible, while conforming to the POSIX standard as well.

この場合、rpmと同様に、シェルスクリプト内で実行したコマンドの終了コードが0以外だった時に、シェルスクリプトが途中終了すると予想していたのですが、#!/bin/shと書いても#!/bin/bashと書いてもどちらも途中終了しませんでした。(少なくともCentOS7では)。||:がなくても、crontab -u taro -l && crontab -u taro -rとだけ書いていれば、最初のコマンドの終了コードが0以外でもシェルスクリプトは動作を継続するようです。

このブログを検索

QooQ