Як я можу використовувати su для виконання решти скрипту bash як цього користувача?


126

Я написав сценарій, який приймає в якості аргументу рядок, що є об'єднанням імені користувача та проекту. Сценарій повинен перейти (su) на ім'я користувача, cd у певний каталог, заснований на рядку проекту.

Я в основному хочу зробити:

su $USERNAME;  
cd /home/$USERNAME/$PROJECT;  
svn update;  

Проблема в тому, що як тільки я роблю су ... це просто чекає. Що має сенс, оскільки потік виконання перейшов до переходу на користувача. Щойно я виходжу, тоді решта речей виконується, але це не працює так, як потрібно.

Я передчував su для команди svn, але команда не вдалася (тобто вона не оновила svn в потрібному каталозі).

Як написати сценарій, що дозволяє користувачеві перемикати користувача та викликати svn (серед іншого)?

Відповіді:


86

Хитрість полягає у використанні команди "sudo" замість "su"

Можливо, вам доведеться додати це

username1 ALL=(username2) NOPASSWD: /path/to/svn

у файл / etc / sudoers

і змініть свій сценарій на:

sudo -u username2 -H sh -c "cd /home/$USERNAME/$PROJECT; svn update" 

Якщо username2 - це користувач, якому потрібно запустити команду SVN, а username1 - це користувач, що виконує сценарій.

Якщо для запуску цього сценарію вам потрібно кілька користувачів, використовуйте %groupnameзамість імені користувача1


У мене є аналогічна проблема, але я хотів запустити chshінших користувачів. Моя проблема перерахована тут на сайті stackoverflow.com/q/15307289/80353 Як я можу адаптувати вашу відповідь у своїй ситуації?
Кім Стек

Я це зробив - але все-таки запитав мене паролем.
Hippyjim

@Hippyjim Ви впевнені, що правильно знайшли імена користувачів?
Кімвайс

1
Я зробив - виявляється, мені теж потрібно було дозволити використання / bin / bash.
Hippyjim

3
Чи використовуєте ви sudoабо suмає другорядне значення, хоча і sudoє набагато більш безпечним і зручним.
трійчатка

105

Набагато простіше: використовувати sudoдля запуску оболонку і використовувати heredoc для подачі її команд.

#!/usr/bin/env bash
whoami
sudo -i -u someuser bash << EOF
echo "In"
whoami
EOF
echo "Out"
whoami

(відповідь спочатку на SuperUser )


5
Ця відповідь спрацювала найкраще. Я рекомендую використовувати варіант, -iщоб отримати someuserочікуване середовище.
not2savvy

2
sudoЦе може бути зручно, але це не добре, якщо його немає поза коробкою (як на AIX). su -c 'commands'є правильною відповіддю.
Хитрий

1
Епічне рішення!
3bdalla

Як зробити змінні доступними в області herdoc?
дотлашлу

на AIX він викидає цю помилку ksh: sh: 0403-006 Виконання дозволу відхилено.
АхмедРана

54

Використовуйте такий сценарій, як наступний, щоб виконати решту або частину сценарію під іншим користувачем:

#!/bin/sh

id

exec sudo -u transmission /bin/sh - << eof

id

eof

11
Ви можете використовувати "sudo -i -u ...", щоб переконатися, що такі речі, як $ HOME, встановлені правильно.
Брайан Ларсен

Вибачте за питання про noob, але який тут ідентифікатор?
Нітін Ядхав

1
@NitinJadhav, він використовував його тут просто для того, щоб показати ідентифікатор поточного користувача, ідентифікатор root - 0, тому перший ідентифікатор покаже вам деяке число, а другий, безумовно, покаже 0 (тому що другий був виконаний всередині блок, виконаний коренем). Ви можете користувачеві whoamiзамість idякого повернути ім'я замість ідентифікатора
Mohammed Noureldin

@MohammedNoureldin Дякую!
Нітін Ядхав

sudoЦе може бути зручно, але це не добре, якщо його немає поза коробкою (як на AIX). su -c 'commands'є правильною відповіддю.
Хитрий

52

Вам потрібно виконати всі команди різних користувачів як власний сценарій. Якщо це лише одна або декілька команд, то вбудована лінія повинна працювати. Якщо команд багато, то, ймовірно, найкраще перемістити їх у власний файл.

su -c "cd /home/$USERNAME/$PROJECT ; svn update" -m "$USERNAME" 

4
Це єдина правильна відповідь. Судо для цього не потрібно.
helvete

1
Вам може знадобитися також забезпечити оболонку su -s /bin/bash.
міксель

найкраще рішення для користувачів root
rfinz

Найкраща відповідь для тих, хто не встановив судо за замовчуванням (дивлюся на вас AIX)
Tricky

46

Ось ще один підхід, який був зручнішим у моєму випадку (я просто хотів скинути привілеї root та виконати решту мого сценарію від обмеженого користувача): ви можете змусити скрипт перезапустити себе від потрібного користувача. Припустимо, він запускається як корінь спочатку. Тоді це буде виглядати приблизно так:

#!/bin/bash
if [ $UID -eq 0 ]; then
  user=$1
  dir=$2
  shift 2     # if you need some other parameters
  cd "$dir"
  exec su "$user" "$0" -- "$@"
  # nothing will be executed beyond that line,
  # because exec replaces running process with the new one
fi

echo "This will be run from user $UID"
...

6
Цікаво, чому це не вище рейтинг. Це вирішення оригінального питання найкраще, зберігаючи все в басі.
СерВер

Або runuser -u $user -- "$@", як сказано в su (1)
cghislai

1
exec su "$user" "$0" -- "$@"
macieksk

1
Дякую @macieksk, приємний улов. Буде оновлено. Це --дійсно корисно.
MarSoft

1
Представлений підхід найкращий з усіх і є завершеним. Все написано всередині одного сценарію, і все використовує bash. Ефективно цей сценарій запускається двічі. Спочатку тест скрипту він є root, потім підготуйте середовище та змініть користувача на su. Але робіть це за допомогою команди exec, тоді є лише один екземпляр сценарію. З другою петлею, фразу if / fi заборонено, тоді сценарій безпосередньо виконує підготовлені дії. У цьому прикладі це відлуння. Усі інші підходи вирішують проблему лише частково. Звичайно, цей сценарій можна запустити під sh не bash, але ми повинні перевірити спеціальну змінну $ HOME, а не $ UID
Znik

7

Використовуйте sudoзамість цього

EDIT : Як Дуглас зазначив, ви не можете використовувати cdв , sudoтак як він не є зовнішньою командою. Щоб виконати роботу, вам потрібно запустити команди в підшах cd.

sudo -u $USERNAME -H sh -c "cd ~/$PROJECT; svn update"

sudo -u $USERNAME -H cd ~/$PROJECT
sudo -u $USERNAME svn update

Вас можуть попросити ввести пароль цього користувача, але лише один раз.


Це не спрацює - компакт-диск буде загублений після того, як перше судо закінчиться виконувати.
Дуглас Лідер

Насправді, ви навіть не можете викликати компакт-диск безпосередньо, оскільки це не зовнішня команда.
iamamac

sudoЦе може бути зручно, але це не добре, якщо його немає поза коробкою (як на AIX). su -c 'commands'є правильною відповіддю.
Хитрий

6

Змінити користувача в сценарії оболонки неможливо. Обхідні шляхи використання судо, описаного в інших відповідях, мабуть, найкраща ставка.

Якщо ви зліли, щоб запустити сценарії perl як root, ви можете це зробити за допомогою $< $( $> $) змінних, які містять реальний / ефективний uid / gid, наприклад:

#!/usr/bin/perl -w
$user = shift;
if (!$<) {
    $> = getpwnam $user;
    $) = getgrnam $user;
} else {
    die 'must be root to change uid';
}
system('whoami');

-1 , як це IS можна з Судом тимчасово отримати права інших користувачів.
Кімвай

4
Це неможливо в тому сенсі, що користувач сам сценарій оболонки запускається, оскільки його неможливо змінити (саме так задається оригінальне запитання). Викликання інших процесів за допомогою sudo не змінює того, ким працює сам сценарій.
P-Nuts

2

Це працювало для мене

Я розділив своє "резервування" від мого "запуску".

 # Configure everything else ready to run 
  config.vm.provision :shell, path: "provision.sh"
  config.vm.provision :shell, path: "start_env.sh", run: "always"

то в моєму start_env.sh

#!/usr/bin/env bash

echo "Starting Server Env"
#java -jar /usr/lib/node_modules/selenium-server-standalone-jar/jar/selenium-server-standalone-2.40.0.jar  &
#(cd /vagrant_projects/myproj && sudo -u vagrant -H sh -c "nohup npm install 0<&- &>/dev/null &;bower install 0<&- &>/dev/null &")
cd /vagrant_projects/myproj
nohup grunt connect:server:keepalive 0<&- &>/dev/null &
nohup apimocker -c /vagrant_projects/myproj/mock_api_data/config.json 0<&- &>/dev/null &

-2

Натхненний ідеєю від @ MarSoft, але я змінив рядки на зразок наступного:

USERNAME='desireduser'
COMMAND=$0
COMMANDARGS="$(printf " %q" "${@}")"
if [ $(whoami) != "$USERNAME" ]; then
  exec sudo -E su $USERNAME -c "/usr/bin/bash -l $COMMAND $COMMANDARGS"
  exit
fi

Я використовував sudoдля дозволу виконання пароля менше виконання сценарію. Якщо ви хочете ввести пароль для користувача, видаліть sudo. Якщо вам не потрібні змінні середовища, видаліть-E із sudo.

У /usr/bin/bash -lгарантує, що profile.dсценарії виконуються для ініціалізованих середовищ.


sudoЦе може бути зручно, але це не добре, якщо його немає поза коробкою (як на AIX). su -c 'commands'є правильною відповіддю.
Хитрий

@Tricky Можливо, прочитайте повну відповідь, вона вже пропонує видалити sudo. Насправді, sudo не такий простий, у багатьох випадках вам потрібен рівний sudo -Eі конфігураційний запис у sudoers.d, щоб дозволити виконання без tty з !requiretty. Але є маса випадків, коли sudo необхідний для автоматичних скриптів, що викликаються, де діалог паролів може заважати. Таким чином, я б не видаляв це зі стандартного рішення.
Trendfischer

Код, про який йде мова, прямо баггі - він розбиває назви сценаріїв або аргументи пробілами; майте на увазі, що розміщення "$@"всередині рядка означає, що аргументи, що передують першому, додаються в окремий рядок, не включений в -cаргумент. Якщо ви хочете зробити це безпечним, ви можете, printf -v arg_q '%q ' "$0" "$@"а потім скористайтесяsu "$USERNAME" -c "/usr/bin/bash -l $arg_q"
Чарльз Даффі,

@CharlesDuffy Ви маєте рацію! Я занадто сильно спростив свій сценарій виробництва для цієї відповіді :-( Просто додавання COMMANDARGS=$@вирішує проблему -c. Аргументи з пробілами раніше не були проблемою, але я реалізував ваш хороший вклад. Мені просто довелося провести кілька експериментів, щоб він працював. Я я редагував питання, і, сподіваюся, я не
вставив
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.