LoginSignup
10
11

More than 5 years have passed since last update.

環境変数 USERNAME で実行ユーザーを取得するワナ

Posted at

Zsh (と Python) の小ネタです。

事件

ある日、Windows 環境で使われている Python スクリプトを受け取りました。しかし手元の Ubuntu で実行したところ動作せず。トレースバックによるとスクリプトの実行ユーザー名を取得する処理で環境変数 USERNAME を参照、KeyError が発生していました。

Traceback (most recent call last):
[...]
    return os.environ["USERNAME"]
  File "/usr/lib/python2.7/UserDict.py", line 23, in __getitem__
    raise KeyError(key)
KeyError: 'USERNAME'

たしか Unix で実行ユーザー名がセットされるのは環境変数 USER でなかったか? Zsh で確認してみよう。

$ echo "<$USER>"
<taro>
$ echo "<$USERNAME>"
<taro>

おやおや、今時の Unix では USERNAME も定義されているのか。ではなぜ Python スクリプトから参照できないのか。

調査

チクチクチク ポーン💡

判明

わかりました。$USERNAME は Zsh 固有のパラメータでした。Zsh から参照できますが子プロセスには渡りません。

$ dash -c 'echo "<$USERNAME>"'
<>
$ bash -c 'echo "<$USERNAME>"'
<>
$ zsh -c 'echo "<$USERNAME>"'
<taro>

man zshparam で zsh のマニュアルを見ると詳細が書いてあります。

       USERNAME <S>
              The  username  corresponding  to  the  real user ID of the shell
              process.  If you have sufficient privileges, you may change  the
              username  (and  also  the  user ID and group ID) of the shell by
              assigning to this parameter.  Also (assuming  sufficient  privi-
              leges),  you  may start a single command under a different user-
              name (and user ID and group  ID)  by  `(USERNAME=username;  com-
              mand)'

教訓

環境変数 USERNAME は Windows で有効ですが Unix ではの利用は控えましょう。代わりに環境変数 USER を参照しましょう。

おまけ

そもそも Python で実行ユーザー名を取得するときは環境変数ではなく getpass モジュールの getuser() 関数を使いましょう。ソースコードを見ると環境変数の LOGNAME, USER, LNAME, USERNAME を順に参照していることがわかります。(LNAME って何だ?)

/usr/lib/python/getpass.py より抜粋:

def getuser():
    """Get the username from the environment or password database.

    First try various environment variables, then the password
    database.  This works on Windows as long as USERNAME is set.

    """

    import os

    for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
        user = os.environ.get(name)
        if user:
            return user

    # If this fails, the exception will "explain" why
    import pwd
    return pwd.getpwuid(os.getuid())[0]

まとめ

実行ユーザー名を取得する場合、

  • Windows なら環境変数 USERNAME を参照する。
  • Unix なら環境変数 USER を参照する。
  • Python なら getpass.getuser() を使う。
10
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
11