su를 사용하여 나머지 bash 스크립트를 해당 사용자로 실행하려면 어떻게해야합니까?


126

사용자 이름과 프로젝트를 연결 한 문자열을 인수로 사용하는 스크립트를 작성했습니다. 스크립트는 (su)를 사용자 이름으로 바꾸고 cd는 프로젝트 문자열을 기반으로 특정 디렉토리로 전환해야합니다.

나는 기본적으로하고 싶다 :

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

문제는 일단 내가 su를하면 ... 그냥 거기에서 기다린다는 것입니다. 실행 흐름이 사용자에게 전환되기 때문에 의미가 있습니다. 일단 종료하면 나머지 작업은 실행되지만 원하는대로 작동하지 않습니다.

svn 명령 앞에 su를 추가했지만 명령이 실패했습니다 (즉, 원하는 디렉토리에서 svn을 업데이트하지 않았습니다).

사용자가 사용자를 전환하고 svn을 호출 할 수있는 스크립트를 작성하려면 어떻게해야합니까?

답변:


86

트릭은 "su"대신 "sudo"명령을 사용하는 것입니다.

이것을 추가해야 할 수도 있습니다.

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

/ etc / sudoers 파일에

스크립트를 다음과 같이 변경하십시오.

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

여기서 username2는 SVN 명령을 실행할 사용자이고 username1은 스크립트를 실행하는 사용자입니다.

이 스크립트를 실행하기 위해 여러 사용자가 필요한 경우 %groupnameusername1 대신 a 를 사용하십시오.


비슷한 문제가 있지만 chsh다른 사용자 를 위해 실행 하고 싶었습니다 . 내 문제는 여기 stackoverflow.com/q/15307289/80353에 나열되어 있습니다 . 내 상황에서 답변을 어떻게 조정합니까?
김 스택

이 작업을 수행했지만 여전히 암호를 요청했습니다.
Hippyjim 2013 년

@Hippyjim 당신은 올바른 방법으로 사용자 이름을 가지고 있다고 확신합니까?
Kimvais

1
나는했다-나는 또한 / bin / bash의 사용을 허용해야한다는 것이 밝혀졌다.
Hippyjim 2013 년

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 2018

Herdoc의 범위에서 변수를 사용 가능하게 만드는 방법은 무엇입니까?
dotslashlu

AIX에서는 다음 오류가 발생합니다. ksh : sh : 0403-006 실행 권한이 거부되었습니다.
AhmedRana

54

다음과 같은 스크립트를 사용하여 다른 사용자로 스크립트의 나머지 또는 일부를 실행합니다.

#!/bin/sh

id

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

id

eof

11
$ HOME과 같은 항목이 올바르게 설정되었는지 확인하려면 "sudo -i -u ..."를 사용할 수 있습니다.
Bryan Larsen

멍청한 질문에 대해 미안하지만 여기에 ID가 무엇입니까?
Nitin Jadhav

1
@NitinJadhav, 그는 현재 사용자의 ID를 표시하기 위해 여기에서 사용했으며 루트의 ID는 0이므로 첫 번째 ID는 숫자를 표시하지만 두 번째 ID는 분명히 0을 표시합니다 (두 번째는 내부에서 실행 되었기 때문). 루트에 의해 실행되는 블록). 당신은 사용자 수 whoami대신에 id대신 ID의 이름을 반환하는
모하메드 Noureldin

@MohammedNoureldin 감사합니다!
Nitin Jadhav

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

루트 사용자를위한 최적의 솔루션
rfinz

기본적으로 sudo를 설치하지 않은 사람들을위한 베스트 답변 (AIX를보고 있습니다)
Tricky

46

제 경우에는 더 편리한 또 다른 접근 방식이 있습니다 (루트 권한을 삭제하고 제한된 사용자로부터 나머지 스크립트를 수행하고 싶었습니다). 올바른 사용자로부터 스크립트를 다시 시작할 수 있습니다. 처음에 루트로 실행되었다고 가정 해 보겠습니다. 그러면 다음과 같이 보일 것입니다.

#!/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 2016-06-04

또는 runuser -u $user -- "$@"su (1)
cghislai에

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

1
감사합니다 @macieksk, 좋은 캐치. 업데이트됩니다. 는 --정말 유용합니다.
MarSoft

1
제시된 접근 방식은 무엇보다도 최고이며 완전합니다. 모두 단일 스크립트 내에 작성되며 모두 bash를 사용합니다. 실제로이 스크립트는 두 번 실행됩니다. 첫 번째 스크립트 테스트에서는 루트이고 환경을 준비하고 su로 사용자를 변경합니다. 그러나 exec 명령으로 수행하면 단일 스크립트 인스턴스 만 있습니다. 두 번째 루프를 사용하면 if / fi 구문이 생략되고 스크립트가 직접 준비된 작업을 수행합니다. 이 예에서는 에코입니다. 다른 모든 접근 방식은 문제를 부분적으로 만 해결합니다. 물론이 스크립트는 bash가 아닌 sh에서 실행할 수 있지만 $ UID가 아닌 $ HOME 특수 변수를 테스트해야합니다
Znik

7

사용 sudo하는 대신

편집 : Douglas가 지적했듯이 외부 명령 이 아니기 때문에 cdin을 사용할 수 없습니다 . 작업을 수행하려면 하위 쉘에서 명령을 실행해야합니다 .sudocd

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

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

해당 사용자의 암호를 입력하라는 메시지가 표시 될 수 있지만 한 번만 입력해야합니다.


그래도 작동하지 않습니다-첫 번째 sudo가 실행을 마친 후에 cd가 손실됩니다.
Douglas Leeder 2010-01-01

실제로 외부 명령 이 아니기 때문에 cd를 직접 호출 할 수도 없습니다 .
iamamac

sudo편리 할 수도 있지만 (AIX에서와 같이) 즉시 사용하지 않으면 좋지 않습니다. su -c 'commands'정답입니다.
Tricky

6

쉘 스크립트 내에서 사용자를 변경할 수 없습니다. 다른 답변에 설명 된 sudo를 사용하는 해결 방법은 아마도 가장 좋은 방법입니다.

펄 스크립트를 루트로 실행하기에 충분히 화를 내면 $< $( $> $) 실제 / 유효 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 가능한 sudo를 일시적으로 다른 유저의 권한을 획득.
Kimvais

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. 환경 변수가 필요하지 않은 경우 -Esudo 에서 제거하십시오 .

/usr/bin/bash -l보장 것을 profile.d스크립트가 초기화 된 환경에서 실행됩니다.


sudo편리 할 수도 있지만 (AIX에서와 같이) 즉시 사용하지 않으면 좋지 않습니다. su -c 'commands'정답입니다.
Tricky

@Tricky 아마도 전체 답변을 읽으면 이미 sudo. 실제로 sudo는 그렇게 간단하지 않습니다. 많은 경우에 sudo -Etty없이 실행할 수 있도록 sudoers.d의 구성 항목 이 필요합니다 !requiretty. 그러나 암호 대화 상자가 방해 할 수있는 자동 호출 스크립트에 sudo가 필요한 경우가 많이 있습니다. 따라서 표준 솔루션에서 제거하지 않을 것입니다.
Trendfischer

문제의 코드는 완전히 버그가 있습니다. 스크립트 이름이나 인수를 공백으로 깨뜨립니다. 퍼팅 것을 명심 "$@"첫 번째 과거 인수는 별도의 문자열로 추가되는 문자열 수단의 내부를, 하지 에 포함 -c인수입니다. 당신은 그것을 안전하게 당신이 수도 싶었다면 printf -v arg_q '%q ' "$0" "$@"다음 사용su "$USERNAME" -c "/usr/bin/bash -l $arg_q"
찰스 더피를

@CharlesDuffy 당신이 맞아요! 나는이 대답을 위해 제작 스크립트를 너무 단순화했습니다 :-( 그냥 추가하면 COMMANDARGS=$@문제가 해결됩니다 -c. 공백이있는 인수는 이전에는 문제가 없었지만 좋은 입력을 구현했습니다. 작동하도록 몇 가지 실험을해야했습니다. '질문을 편집했습니다 희망 나는 또 다른 버그를 붙여하지 않은 감사 의견, 굴욕하지만 필요합니다..
Trendfischer
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.