シェルスクリプトでユーザーやグループの存在を判定したいときは、getentの終了コードを使う。
check() {
if getent passwd "$1" >/dev/null; then
echo "$1 exists"
else
echo "$1 missing"
fi
}
見つかれば終了コードが0、見つからなければ2になる。標準出力は不要なので、>/dev/nullで捨てる。aliceだけが存在する環境での実行例はこうなる。実行例はUbuntu 24.04(glibc 2.39)のもの。
$ check alice
alice exists
$ check bob
bob missing
終了コードの一覧
getentの終了コードは以下のとおり。
| 終了コード | 意味 | 例 |
|---|---|---|
| 0 | 見つかった | getent passwd alice |
| 1 | 引数の数が不正、または存在しないデータベース名 | getent、getent foo bar |
| 2 | キーが見つからない | getent passwd nosuch |
| 3 | 全件の列挙に対応していないデータベース | getent ethers |
$ getent passwd alice >/dev/null; echo $?
0
$ getent passwd nosuch >/dev/null; echo $?
2
$ getent; echo $?
getent: wrong number of arguments
Try `getent --help' or `getent --usage' for more information.
1
$ getent ethers; echo $?
Enumeration not supported on ethers
3
存在判定では、0と2を区別すれば足りる。
ユーザーやグループが無いときだけ作る
||でつなぐと、存在しないときだけuseraddやgroupaddを実行できる。スクリプトを何度実行しても同じ結果になる。
getent passwd "$user" >/dev/null || useradd -m "$user"
getent group "$group" >/dev/null || groupadd "$group"
useraddとgroupaddは、既に存在するとエラーメッセージを出して終了コード9で失敗する。getentで事前に確認すれば、set -eを使ったスクリプトでも止まらない。
変数が空のとき全件が出力される
getent passwdは、引数を省略すると全ユーザーを表示して終了コード0を返す。変数をダブルクォートで囲まずに展開し、変数が空だと引数が無くなり、存在判定が常に成功する。
$ user=""
$ getent passwd $user | wc -l
20
$ getent passwd $user >/dev/null; echo $?
0
変数はダブルクォートで囲む。空文字列も引数として渡されるため、終了コードは2になる。
$ getent passwd "$user" >/dev/null; echo $?
2
UIDやGIDで判定する
引数にはUIDやGIDも渡せる。UIDやGIDが使われているかどうかを確認できる。
$ getent passwd 1001 >/dev/null; echo $?
0
$ getent group 9999 >/dev/null; echo $?
2
複数の引数をまとめて判定する
引数を複数並べたときは、すべて見つかると終了コードが0になる。1つでも見つからないと、他が見つかっていても2になる。
$ getent passwd root nobody >/dev/null; echo $?
0
$ getent passwd alice nosuch >/dev/null; echo $?
2
複数のユーザーが揃っているかを、1回のコマンドで確認できる。どのユーザーが無いかを知りたいときは、1人ずつ判定する。
idやgrepとの違い
ユーザーの存在判定にはidやgrepもよく使われる。
$ id alice >/dev/null 2>&1; echo $?
0
$ id nosuch >/dev/null 2>&1; echo $?
1
$ grep -q '^alice:' /etc/passwd; echo $?
0
idは存在しないときの終了コードが1で、getentの2とは異なる。grep /etc/passwdは、/etc/passwdに書かれたユーザーしか見つけられない。getentは/etc/nsswitch.confの参照元すべてを引くので、LDAPやSSSDなどのディレクトリサービスにいるユーザーも判定できる。
権限が無いときも終了コードは2になる
一般ユーザーがgetent shadowを実行すると、権限が無いために読めない。この場合も、エントリが無いときと同じ終了コード2になる。
$ getent shadow alice; echo $?
2
shadowで終了コード2が返ったときは、エントリが無いのか、権限が無いのかを区別できない。
参考: 【getent】パスワードハッシュや有効期限を確認する (shadow/gshadow)
ホスト名が解決できるかを判定する
getent hostsでも同じように判定できる。名前解決できない場合は終了コードが2になる。
$ getent hosts localhost >/dev/null; echo $?
0
$ getent hosts nonexist.invalid >/dev/null; echo $?
2
参考: 【getent】/etc/hostsを含む実際の名前解決の結果を確認する (hosts)
initgroupsは存在判定に使えない
getent initgroupsは、存在しないユーザーを指定しても終了コードが0になる。ユーザーの存在判定はgetent passwdで行う。
参考: 【getent】グループのメンバーや所属グループを調べる (group/initgroups)
