Как использовать 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, вы уверены, что правильно выбрали имена пользователей?
Kimvais

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

3
Независимо от того, используете ли вы sudoили suимеет второстепенное значение, sudoэто намного безопаснее и удобнее.
Tripleee

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'это правильный ответ.
Tricky

1
Эпическое решение!
3bdalla

Как сделать переменные доступными в рамках Herdoc?
dotslashlu

в AIX эта ошибка выдается ksh: sh: 0403-006 Отказано в разрешении на выполнение.
AhmedRana

54

Используйте сценарий, подобный следующему, для выполнения остальной части сценария или его части под другим пользователем:

#!/bin/sh

id

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

id

eof

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

Извините за вопрос нуба, но что здесь за идентификатор?
Нитин Джадхав

1
@NitinJadhav, он использовал его здесь, чтобы показать идентификатор текущего пользователя, идентификатор root равен 0, поэтому первый идентификатор покажет вам какое-то число, но второй определенно покажет 0 (потому что второй был выполнен внутри блок, запускаемый root). Вы можете user, whoamiвместо idкоторого будет возвращать имя вместо id
Мохаммед Нурелдин

@MohammedNoureldin Спасибо!
Нитин Джадхав

sudoможет быть удобно, но не годится, если он не из коробки (как в AIX). su -c 'commands'это правильный ответ.
Tricky

52

Вам необходимо выполнить все команды для разных пользователей как отдельный сценарий. Если это всего одна или несколько команд, то встроенный должен работать. Если команд много, то, вероятно, лучше переместить их в отдельный файл.

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

4
Это единственно правильный ответ. Для этого sudo не требуется.
helvete

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

лучшее решение для root-пользователей
rfinz

Лучший ответ для тех, у кого sudo не установлен по умолчанию (я смотрю на вас, AIX)
Tricky

46

Вот еще один подход, который в моем случае был более удобен (я просто хотел отказаться от привилегий root и выполнить остальную часть сценария от ограниченного пользователя): вы можете перезапустить сценарий от правильного пользователя. Предположим, что он изначально запущен как 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
Интересно, почему это не выше рейтинга. Он лучше всего решает исходный вопрос, сохраняя при этом все в bash.
SirVer 04

Или 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
Зник

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

Вас могут попросить ввести пароль этого пользователя, но только один раз.


Однако это не сработает - компакт-диск будет потерян после завершения выполнения первого sudo.
Дуглас Лидер 01

Фактически, вы даже не можете вызвать cd напрямую, потому что это не внешняя команда.
iamamac 01

sudoможет быть удобно, но не годится, если он не из коробки (как в AIX). su -c 'commands'это правильный ответ.
Tricky

6

Сменить пользователя в сценарии оболочки невозможно. Обходные пути с использованием sudo, описанные в других ответах, вероятно, будут вашим лучшим выбором.

Если вы достаточно безумны, чтобы запускать сценарии 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 можно с Судом временно получить права других пользователей.
Kimvais 01

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,

@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. Аргументы с пробелами не были проблемой раньше, но я реализовал ваш хороший ввод. Мне просто пришлось провести несколько экспериментов, чтобы заставить его работать. Я отредактировал вопрос и, надеюсь, я не вставил еще одну ошибку. Спасибо за ваш комментарий, унизительный, но необходимый.
Trendfischer
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.