Відповіді:
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[@]};
...