Risposte:
sudo su -
, che è un modo complicato di scrivere sudo -i
, costruisce un ambiente incontaminato. Questo è il punto di una shell di login. Anche un piano sudo
rimuove la maggior parte delle variabili dall'ambiente. Inoltre sudo
è un comando esterno; non c'è modo di elevare i privilegi nello stesso script di shell, solo per eseguire un programma esterno ( sudo
) con privilegi extra, e ciò significa che qualsiasi variabile di shell (ovvero variabili non esportate) e le funzioni definite nella shell padre non saranno disponibili in il guscio del bambino.
È possibile passare attraverso le variabili di ambiente non invocando una shell di login ( sudo bash
invece di sudo su -
o sudo -i
) e configurando sudo per far passare queste variabili (con Defaults !env_reset
o Defaults env_keep=…
nel sudoers
file). Questo non ti aiuterà per le funzioni (sebbene bash abbia una funzione di esportazione delle funzioni, sudo la blocca).
Il modo normale di ottenere le funzioni nella shell figlio sarebbe definirle lì. Abbi cura di citare: se usi <<EOF
per il documento here, il contenuto del documento here viene prima espanso dalla shell genitore e il risultato di tale espansione diventa lo script che vede la shell figlio. Cioè, se scrivi
sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
questo visualizza il nome dell'utente originale, non dell'utente di destinazione. Per evitare questa prima fase di espansione, citare il marcatore del documento qui dopo l' <<
operatore:
sudo -u "$target_user" -i <<'EOF'
echo "$(whoami)"
EOF
Quindi, se non è necessario passare i dati dalla shell padre alla shell figlio, è possibile utilizzare un documento citato qui:
#!/bin/bash
sudo -u "$target_user" -i <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}"
EOF
Sebbene sia possibile utilizzare un marcatore di documenti qui non quotato per passare i dati dalla shell padre alla shell figlio, questo funziona solo se i dati non contengono alcun carattere speciale. Questo perché in una sceneggiatura simile
sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
l'output di whoami
diventa un po 'di codice shell, non una stringa. Ad esempio, se il whoami
comando restituito, "; rm -rf /; "true
la shell figlio eseguirà il comando echo ""; rm -rf /; "true"
.
Se è necessario passare i dati dalla shell padre, un modo semplice è passarli come argomenti. Richiamare esplicitamente la shell figlio e passargli i parametri posizionali:
#!/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 hai più variabili da passare, sarà più leggibile passarle per nome. Chiamare env
esplicitamente per impostare le variabili di ambiente per la shell figlio.
#!/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
Tieni presente che se ti aspettavi /etc/profile
che l'utente di destinazione ~/.profile
fosse letto, dovrai leggerli esplicitamente o chiamare bash --login
invece di sh
.
Questo non funziona perché la funzione log_f
non è dichiarata nella sudo su -
shell che si avvia. Anziché:
extVAR="yourName"
sudo su - <user> << EOF
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f ${intVAR} ${extVAR}
EOF
È necessario ottenere la funzione definita nella subshell radice. Potrebbe farlo, ma .... Non so cosa faccia la maggior parte di quella roba. Almeno - fino a quando non sudo
ne su
esigenze stdin di leggere una password - che dovrebbe ottenere log_f()
dichiarata.
Confido che intendi espandere quei valori nell'input della shell di root, comunque. Se non intendi farlo, allora dovresti citare EOF
e gli stessi.
Nel mio caso avevo bisogno di passare un array e ho avuto qualche problema, ma dopo un po 'ho avuto successo riecheggiando i valori dell'array in un env
-key e avvolgendo il codice desiderato bash -c '<intended code>'
, e fondamentalmente facendolo ricreare l'array, ad es INNER_KEY=($<env_key>)
. : .
Per esame:
#!/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
Il problema era che non potevo fare direttamente qualcosa del tipo (non usando bash -c '...'
):
FOO=($PLUGINS);
for pl in ${FOO[@]};
...