Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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() を使う。
quenhulu
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした