シェルスクリプトでユーザーやグループの存在を判定したいときは、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)