Respostas:
sudo su -
, que é uma maneira complicada de escrever sudo -i
, constrói um ambiente primitivo. Esse é o objetivo de um shell de login. Mesmo uma planície sudo
remove a maioria das variáveis do ambiente. Além disso, sudo
é um comando externo; não há como elevar privilégios no próprio script do shell, apenas para executar um programa externo ( sudo
) com privilégios extras, e isso significa que quaisquer variáveis do shell (ou seja, variáveis não exportadas) e funções definidas no shell pai não estarão disponíveis no a concha do filho.
Você pode passar variáveis de ambiente não invocando um shell de login (em sudo bash
vez de sudo su -
ou sudo -i
) e configurando o sudo para permitir que essas variáveis passem (com Defaults !env_reset
ou Defaults env_keep=…
no sudoers
arquivo). Isso não ajudará você em funções (embora o bash tenha um recurso de exportação de funções, o sudo o bloqueia).
A maneira normal de obter suas funções no shell filho seria defini-las lá. Lembre-se de citar: se você usar <<EOF
o documento here, o conteúdo do documento here será expandido primeiro pelo shell pai, e o resultado dessa expansão se tornará o script que o shell filho visualiza. Ou seja, se você escrever
sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
isso exibe o nome do usuário original, não o usuário de destino. Para evitar essa primeira fase de expansão, cite o marcador de documento aqui após o <<
operador:
sudo -u "$target_user" -i <<'EOF'
echo "$(whoami)"
EOF
Portanto, se você não precisar passar dados do shell pai para o shell filho, use um documento aqui citado:
#!/bin/bash
sudo -u "$target_user" -i <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}"
EOF
Embora você possa usar um marcador de documento aqui não citado para passar dados do shell pai para o shell filho, isso só funciona se os dados não contiverem nenhum caractere especial. Isso porque em um script como
sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
a saída de whoami
se torna um pouco de código de shell, não uma string. Por exemplo, se o whoami
comando retornasse "; rm -rf /; "true
, o shell filho executaria o comando echo ""; rm -rf /; "true"
.
Se você precisar passar dados do shell pai, uma maneira simples é passá-los como argumentos. Invoque o shell filho explicitamente e passe parâmetros posicionais:
#!/bin/bash
extVAR="yourName"
sudo -u "$target_user" -i sh _ "$extVAR" <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}" "${1}"
EOF
Se você tiver várias variáveis para passar, será mais legível passá-las pelo nome. Chame env
explicitamente para definir variáveis de ambiente para o shell filho.
#!/bin/bash
extVAR="yourName"
sudo -u "$target_user" -i env extVAR="$extVAR" sh <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}" "${1}"
EOF
Observe que, se você esperava que /etc/profile
o usuário de destino ~/.profile
fosse lido, precisará lê-los explicitamente ou ligar em bash --login
vez de sh
.
Isso não funciona porque a função log_f
não está declarada no sudo su -
shell que você inicia. Em vez de:
extVAR="yourName"
sudo su - <user> << EOF
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f ${intVAR} ${extVAR}
EOF
Você precisa obter a função definida no subshell raiz. Isso pode funcionar, mas ... Eu não sei o que a maioria dessas coisas faz. Pelo menos - contanto que sudo
nem o su
stdin precise ler uma senha - isso deve ser log_f()
declarado.
Confio que você pretenda expandir esses valores na entrada do shell raiz, a propósito. Se você não pretende fazê-lo, deve citar EOF
os próprios vars.
No meu caso eu precisava para passar um array e teve alguns problemas, mas teve sucesso depois de um tempo por ecoando os valores da matriz a uma env
tecla e envolvendo o código destina-se em bash -c '<intended code>'
, e, basicamente, tem que recriar o array, por exemplo .: INNER_KEY=($<env_key>)
.
Por exemplo:
#!/usr/bin/env bash
PLUGINS=(foo bar baz)
sudo -u <some-user> -i env PLUGINS="`echo ${PLUGINS[@]}`" sh <<'EOF'
bash -c '
FOO=($PLUGINS);
echo values: \[${FOO[@]}\];
for pl in ${FOO[@]};
do echo value: $pl;
done;
'
EOF
O problema era que eu não podia fazer diretamente algo como o seguinte (não usando bash -c '...'
):
FOO=($PLUGINS);
for pl in ${FOO[@]};
...