sudo su -
, que é uma maneira complicada de escrever sudo -i
, constrói um ambiente primitivo. Esse é o ponto de um shell de login. Mesmo um sudo
simples 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 shell script, apenas para executar um programa externo ( sudo
) com privilégios extras, e isso significa que quaisquer variáveis de shell (ou seja, variáveis não exportadas) e funções definidas no shell pai não estar disponível no shell filho.
Você pode transmitir variáveis de ambiente por meio da não invocação de um shell de login ( sudo bash
em vez de sudo su -
ou sudo -i
) e da configuração do sudo para permitir que essas variáveis passem (com Defaults !env_reset
ou Defaults env_keep=…
no sudoers
Arquivo). Isso não ajudará em funções (embora o bash tenha um recurso de exportação de função, o sudo o bloqueia).
A maneira normal de obter suas funções no shell filho seria defini-las lá. Tome cuidado com as citações: se você usar <<EOF
para o documento here, o conteúdo do documento here é expandido primeiro pelo shell pai e o resultado dessa expansão se torna o script que o shell filho vê. Isto é, se você escreve
sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
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
Então, se você não precisa passar dados do shell pai para o shell filho, você pode usar um documento citado aqui:
#!/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 não mencionado aqui para passar dados do shell pai para o shell filho, isso só funcionará 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 shell, não uma string. Por exemplo, se o comando whoami
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á-lo como argumentos. Invoque o shell filho explicitamente e passe-o aos 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
Se você espera que /etc/profile
e% de% do usuário alvo sejam lidos, será preciso lê-los explicitamente ou chamar ~/.profile
em vez de bash --login
.