Відповіді:
sudo su -, що є складним способом написання sudo -i, будує незаймане середовище. Це сенс оболонки для входу. Навіть звичайна sudoчастина видаляє більшість змінних із середовища. Крім того sudo, це зовнішня команда; у самому скрипті оболонки немає можливості підняти привілеї, лише запустити зовнішню програму ( sudo) з додатковими привілеями, а це означає, що будь-які змінні оболонки (тобто неекспортовані змінні) та функції, визначені в батьківській оболонці, не будуть доступні в дитяча оболонка.
Ви можете передати змінні середовища через не викликаючи оболонку входу ( sudo bashзамість sudo su -або sudo -i) та налаштувавши sudo для пропускання цих змінних через (з Defaults !env_resetабо Defaults env_keep=…у sudoersфайл). Це не допоможе вам для функцій (хоча bash має функцію експорту функцій, sudo блокує його).
Нормальним способом отримання своїх функцій у дочірній оболонці було б визначення їх там. Будьте уважні до цитування: якщо ви використовуєте <<EOFдля документа тут, зміст документа тут спочатку розширюється батьківською оболонкою, і результатом цього розширення стає сценарій, який бачить дочірня оболонка. Тобто, якщо ви пишете
sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
це відображає ім'я початкового користувача, а не цільового користувача. Щоб уникнути цієї першої фази розширення, цитуйте тут маркер документа після <<оператора:
sudo -u "$target_user" -i <<'EOF'
echo "$(whoami)"
EOF
Отже, якщо вам не потрібно передавати дані з батьківської оболонки до дочірньої оболонки, ви можете використовувати цитований тут документ:
#!/bin/bash
sudo -u "$target_user" -i <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}"
EOF
У той час як ви можете використовувати маркер документа, який не котирується тут, для передачі даних від батьківської оболонки до дочірньої оболонки, це працює лише в тому випадку, якщо дані не містять спеціального символу. Це тому, що в такому сценарії, як
sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
Вихідного whoamiкоду стає трохи оболонки, а не рядка. Наприклад, якщо whoamiкоманда повернулася, "; rm -rf /; "trueтоді дочірня оболонка виконала б команду echo ""; rm -rf /; "true".
Якщо вам потрібно передати дані з батьківської оболонки, простий спосіб - передати їх як аргументи. Викликайте дочірню оболонку прямо та передайте їй позиційні параметри:
#!/bin/bash
extVAR="yourName"
sudo -u "$target_user" -i sh _ "$extVAR" <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}" "${1}"
EOF
Якщо у вас є кілька змінних для передачі, буде зручніше їх передавати по імені. envЯвно зателефонуйте, щоб встановити змінні середовища для дочірньої оболонки.
#!/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
Зауважте, що якщо ви очікували, /etc/profileщо цільовий користувач ~/.profileбуде прочитаний, вам доведеться їх прочитати прямо або зателефонувати bash --loginзамість sh.
Це не працює, оскільки функція log_fне оголошена в sudo su -оболонці, яку ви запускаєте. Замість цього:
extVAR="yourName"
sudo su - <user> << EOF
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f ${intVAR} ${extVAR}
EOF
Вам потрібно визначити функцію, визначену в кореневій підзахисті. Це могло б зробити це, але .... я не знаю, чим займається більшість цих речей. Принаймні - до тих пір, поки ні sudoі не suпотрібно stdin, щоб прочитати пароль - це слід log_f()оголосити.
Я вірю, що ви, до речі, маєте намір розширити ці значення на вхід кореневої оболонки. Якщо ви цього не хочете робити, то слід навести EOFі самі вари.
У моєму випадку мені потрібно було передати масив і виникли певні проблеми, але через деякий час я мав успіх, повторивши значення масиву до env-key і загорнувши призначений код bash -c '<intended code>', і, в основному, він відтворив масив, наприклад INNER_KEY=($<env_key>).:
Для іспиту:
#!/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
Проблема полягала в тому, що я не міг безпосередньо зробити щось подібне (не використовуючи bash -c '...'):
FOO=($PLUGINS);
for pl in ${FOO[@]};
...