su - で呼び出すときに非対話型bashログインシェルが/ etc / profileを無視するのはなぜですか?

su - で呼び出すときに非対話型bashログインシェルが/ etc / profileを無視するのはなぜですか?

私は次のように特定のユーザーから始めましたsutmux

$ su - someuser -c tmux

ただし、これにより、次のエラーメッセージが表示されます。

tmux: need UTF-8 locale (LC_CTYPE) but have ANSI_X3.4-1968

このエラーは、LANG環境変数が設定されていないために発生します。新しいものログインシェルこのviaは通常設定されますが、実際に使用が要求され、ログインシェルを作成しているように見えても、/etc/profilethrough呼び出しはsu使用されません。/etc/profilesu -

シェルを使用しているユーザーにはsomeuser機能しませんbash。ただし、dashまたはなどの他のシェルと組み合わせて使用​​できますzsh。対話型bashログインシェルも期待どおりに機能します。

電話するときになぜbash無視されますか?/etc/profile非対話型通過するsu -

私の研究(以下)によると、問題は(および/または)コマンドラインオプションにハイフンを使用することが、他のシェルと比較してbashログインシェルを要求するときに異なる動作をすることです。$0su-l--login


研究

(少し長いが、調査内容を文書として記録したかった。)

man suこの-c引数が使用されることを説明します。

-c オプションを使用してコマンドをシェルに渡します。

そして-議論

シェルをログインシェルで起動します。環境は実際のログインに似ています。

したがって、実際のログインに似た環境のログインシェルで実行する必要がありますsu - someuser -c cmdcmdsomeuser

デモにはテストコマンドを使用できます。

$ testcmd='shopt -q login_shell || echo -n non-; echo login shell $0 $LANG'

suログインと非ログインのシェルに対して、以下を試してください。

$ su - someuser -c "$testcmd"
login shell -bash
$ su someuser -c "$testcmd"
non-login shell bash en_GB.UTF-8

ログインシェルの起動時に環境は構成されません(使用しないLANGため設定しません)。/etc/profile環境は非ログインシェルを起動すると継承されるため、値は事前LANGに消去され、示されているように起動シェルの環境から取得されます。

$ LANG= su someuser -c "$testcmd"
non-login shell bash

上記の例にはシェルがsomeuserありますbash。 (単純なシンボリックリンクです)を使用してsh同じ結果を得ることができますbash。使用すると期待どおりに機能しますzsh

$ ztestcmd='[[ -o login ]] || echo -n non-; echo login shell $LANG'
$ LANG= su - someuser -s /bin/zsh -c "$ztestcmd"
Password: 
login shell -zsh en_GB.UTF-8
$ LANG= su someuser -s /bin/zsh -c "$ztestcmd"
Password: 
non-login shell zsh
su someuser -s /bin/zsh -c "$ztestcmd"
Password: 
non-login shell zsh en_GB.UTF-8

でも動作します。したがって、問題はより深く掘り下げられるようdashです。bashbash

対話型シェルを起動すると、期待どおりに機能します。

$ su - someuser
$ LANG= shopt -q login_shell || echo -n non-; echo login shell $0 $LANG
login shell -bash en_GB.UTF-8

bashしたがって、対話型実行と非対話型実行suは異なる動作をします。bash直接創業はどうですか?

$ LANG= bash -c "$testcmd"
non-login shell bash
$ LANG= bash -l -c "$testcmd"
login shell bash en_GB.UTF-8

これは期待どおりに機能します。

GNU バッシュマニュアル状態それ

Bashが対話型ログインシェルまたはoptionsを含む非対話型シェルとして呼び出されると、--loginまずファイルからコマンドを読み取り、実行します。/etc/profile

manによると、suその-オプションは使用されていませんが、--login代わりに

-シェルをログインシェルにするには、シェルのargv [0]を設定します。

以下を証明できます。

$ su - someuser -c 'echo $0'
Password: 
-bash

私たちはこれを直接テストできます。先行ハイフンは$0ログインシェルを提供します:

$ (LANG= exec -a '-' bash -c "$testcmd")
login shell -

だから先頭ハイフン$0ログインシェルを作成しますが、bash 実行されない/etc/profileこれは、この方法で呼び出されると、そのオプションの動作と一致せず、-l他のシェル(zshまたは)とも一致しませんdash。また、インタラクションの開始時の独自の動作とも一致しません。

$ (LANG= exec -a '-' bash)
$ shopt -q login_shell || echo -n non-; echo login shell $0 $LANG
login shell - en_GB.UTF-8

残念ながら、これは上記の文書と矛盾しません。なぜなら、その使用を定義しないからです-l

ベストアンサー1

コメントに記載されているとおりに正しく機能します。

もう一度考える文書:

Bashが対話型ログインシェルまたはoptionsを含む非対話型シェルとして呼び出されると、--loginまずファイルからコマンドを読み取り、実行します。/etc/profile

/etc/profile読み取りと実行として正しく解釈します。対話型ログインシェルまたは--loginオプションの非対話型シェル$0ハイフンで始まる非対話型ログインシェルとは言いません。

ただし、この動作は意図的に設計された動作であり、コンパイル時オプションのコメントを外すことでコンパイル時に変更できます。構成-top.h:

/* Define this to make non-interactive shells begun with argv[0][0] == '-'
run the startup files when not in posix mode. */
/* #define NON_INTERACTIVE_LOGIN_SHELLS */

しかし、実際にはそうではありませんが、なぜこの動作が実装されるのかについて疑問があります。IMHO、特に他のシェルのように実装されていない場合は、合理的に動作すると期待する方法です。

つまり、私の考えではないと思います。POSIX 標準シェル定義ログインシェルだから説明が可能だと思います。

元の問題に適用される回避策は次のとおりですbash

$ su - someuser -c 'bash -l -c tmux'

おすすめ記事