Estou usando su
para iniciar tmux
como um usuário específico, assim:
$ su - someuser -c tmux
No entanto, isso resulta em uma mensagem de erro:
tmux: need UTF-8 locale (LC_CTYPE) but have ANSI_X3.4-1968
O erro ocorre porque a variável de ambiente LANG
não está definida. Um novo login shell normalmente define isso via /etc/profile
, mas a invocação através de su
não usa /etc/profile
, embora o uso de su -
solicite e pareça produzir um shell de login. / p>
O usuário someuser
para o qual isso não funciona tem o shell bash
. No entanto, ele funciona com outros shells, como dash
ou zsh
. Um shell de login bash
interativo também funciona como esperado.
Por que bash
ignora /etc/profile
quando é invocado não interativamente por meio de su -
?
Minha pesquisa (abaixo) indicaria que o problema é que bash
, em contraste com outros shells, se comporta de maneira diferente quando um shell de login é solicitado com um hífen principal em $0
(o que su
faz) versus -l
(ou --login
) opção de linha de comando.
Pesquisa
(isso é um pouco detalhado, mas eu queria registrar minhas investigações)
man su
explica que o argumento -c
é usado para
Pass command to the shell with the -c option.
e o argumento -
Start the shell as a login shell with an environment similar to a real login
Portanto, su - someuser -c cmd
deve executar cmd
em um shell de login para someuser
com um ambiente semelhante a um login real.
Um comando de teste é útil para demonstrar:
$ testcmd='shopt -q login_shell || echo -n non-; echo login shell $0 $LANG'
Tentando isso com su
para shells de login e não-login:
$ su - someuser -c "$testcmd"
login shell -bash
$ su someuser -c "$testcmd"
non-login shell bash en_GB.UTF-8
Quando um shell de login é iniciado, o ambiente não está configurado ( LANG
não está definido porque /etc/profile
não é usado). O ambiente é herdado de quando um shell não-login é lançado, então o valor de LANG
é aquele do shell de inicialização, já que a limpeza é demonstrada de antemão:
$ LANG= su someuser -c "$testcmd"
non-login shell bash
Nos exemplos acima, someuser
tem o shell bash
. Os mesmos resultados são obtidos com sh
(que é apenas um link simbólico para bash
). Se zsh
for usado, as coisas funcionam conforme o esperado:
$ 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
Também funciona com dash
. Portanto, o problema parece estar com bash
. Investigando bash
...
Funciona como esperado se um shell interativo for lançado:
$ su - someuser
$ LANG= shopt -q login_shell || echo -n non-; echo login shell $0 $LANG
login shell -bash en_GB.UTF-8
Portanto, bash
interativa e não interativa lançada por meio de su
se comporta de maneira diferente. Que tal lançar bash
diretamente?
$ LANG= bash -c "$testcmd"
non-login shell bash
$ LANG= bash -l -c "$testcmd"
login shell bash en_GB.UTF-8
Isso funciona como esperado.
O Manual GNU Bash afirma que
When Bash is invoked as an interactive login shell, or as a non-interactive shell with the --login
option, it first reads and executes commands from the file /etc/profile
De acordo com o homem su
, sua opção -
não usa --login
, mas sim
sets argv[0] of the shell to -
in order to make the shell a login shell
O que pode ser comprovado:
$ su - someuser -c 'echo $0'
Password:
-bash
Podemos testar a nós mesmos que um hífen principal em $0
fornece um shell de login:
$ (LANG= exec -a '-' bash -c "$testcmd")
login shell -
Assim, um hífen principal em $0
produz um shell de login, mas bash
não executa /etc/profile
quando invocado dessa maneira, o que é inconsistente com o comportamento de sua opção -l
e também com outros shells, como zsh
ou dash
. Também é inconsistente com seu próprio comportamento quando lançado interativamente:
$ (LANG= exec -a '-' bash)
$ shopt -q login_shell || echo -n non-; echo login shell $0 $LANG
login shell - en_GB.UTF-8
Infelizmente, isso não está de acordo com a documentação citada acima, porque isso não define o comportamento de um shell de login não interativo que não foi lançado com -l
.