ฉันจะใช้ su เพื่อเรียกใช้สคริปต์ bash ที่เหลือในฐานะผู้ใช้นั้นได้อย่างไร


127

ฉันได้เขียนสคริปต์ที่ใช้เป็นอาร์กิวเมนต์ซึ่งเป็นสตริงที่เชื่อมต่อกันของชื่อผู้ใช้และโครงการ สคริปต์ควรจะเปลี่ยน (su) เป็นชื่อผู้ใช้ cd ไปยังไดเร็กทอรีเฉพาะตามสตริงโครงการ

โดยพื้นฐานแล้วฉันต้องการทำ:

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

ปัญหาคือเมื่อฉันทำซู ... มันก็รออยู่ที่นั่น ซึ่งสมเหตุสมผลตั้งแต่ขั้นตอนการดำเนินการผ่านไปจนถึงการเปลี่ยนไปใช้ผู้ใช้ เมื่อฉันออกจากนั้นสิ่งที่เหลือจะดำเนินการ แต่ไม่ได้ผลตามที่ต้องการ

ฉันนำหน้า su ไปยังคำสั่ง svn แต่คำสั่งล้มเหลว (กล่าวคือไม่ได้อัพเดต svn ในไดเร็กทอรีที่ต้องการ)

ฉันจะเขียนสคริปต์ที่อนุญาตให้ผู้ใช้สลับผู้ใช้และเรียกใช้ svn (เหนือสิ่งอื่นใด) ได้อย่างไร

คำตอบ:


87

เคล็ดลับคือใช้คำสั่ง "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 คือผู้ใช้ที่รันสคริปต์

หากคุณต้องการให้ผู้ใช้หลายคนเรียกใช้สคริปต์นี้ให้ใช้ a %groupnameแทน username1


ฉันมีปัญหาที่คล้ายกัน แต่ฉันต้องการเรียกใช้chshสำหรับผู้ใช้รายอื่น ปัญหาของฉันแสดงไว้ที่stackoverflow.com/q/15307289/80353ฉันจะปรับคำตอบของคุณในสถานการณ์ของฉันได้อย่างไร
Kim Stacks

ฉันทำสิ่งนี้ - แต่ก็ยังขอรหัสผ่าน
Hippyjim

@Hippyjim คุณแน่ใจหรือว่าคุณมีชื่อผู้ใช้ที่ถูกต้อง?
Kimvais

1
ฉันทำ - ปรากฎว่าฉันต้องอนุญาตให้ใช้ / bin / bash ด้วย
Hippyjim

3
ไม่ว่าคุณจะใช้sudoหรือsuมีความสำคัญรองลงมา แต่sudoก็ปลอดภัยและสะดวกกว่ามาก
tripleee

106

ง่ายกว่ามาก: ใช้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 ได้อย่างไร?
dotslashlu

บน AIX จะแสดงข้อผิดพลาดนี้ ksh: sh: 0403-006 Execute permission disabled
AhmedRana

55

ใช้สคริปต์ดังต่อไปนี้เพื่อดำเนินการส่วนที่เหลือหรือบางส่วนของสคริปต์ภายใต้ผู้ใช้รายอื่น:

#!/bin/sh

id

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

id

eof

11
คุณอาจต้องการใช้ "sudo -i -u ... " เพื่อให้แน่ใจว่าสิ่งต่างๆเช่น $ HOME ได้รับการตั้งค่าอย่างถูกต้อง
Bryan Larsen

ขออภัยสำหรับคำถาม noob แต่ id ที่นี่คืออะไร?
Nitin Jadhav

1
@NitinJadhav เขาใช้ที่นี่เพื่อแสดง ID ของผู้ใช้ปัจจุบัน ID ของ root คือ 0 ดังนั้น id แรกจะแสดงหมายเลขให้คุณ แต่อันที่สองจะแสดง 0 อย่างแน่นอน (เนื่องจากอันที่สองถูกเรียกใช้งานภายใน บล็อกที่รันโดยรูท) คุณสามารถใช้whoamiแทนidซึ่งจะส่งคืนชื่อแทนรหัส
Mohammed Noureldin

@MohammedNoureldin ขอบคุณ!
Nitin Jadhav

sudoอาจสะดวก แต่ก็ไม่ดีหากไม่ได้อยู่นอกกรอบ (เช่นบน AIX) su -c 'commands'คือคำตอบที่ถูกต้อง
หากิน

53

คุณต้องดำเนินการคำสั่งผู้ใช้ที่แตกต่างกันทั้งหมดเป็นสคริปต์ของตัวเอง หากเป็นเพียงคำสั่งเดียวหรือสองสามคำสั่งแบบอินไลน์ก็ควรใช้งานได้ หากมีคำสั่งมากมายก็ควรย้ายไปที่ไฟล์ของตัวเอง

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

นี่เป็นอีกวิธีหนึ่งซึ่งสะดวกกว่าในกรณีของฉัน (ฉันแค่ต้องการลดสิทธิ์รูทและทำสคริปต์ที่เหลือจากผู้ใช้ที่ถูก จำกัด ): คุณสามารถทำให้สคริปต์รีสตาร์ทเองจากผู้ใช้ที่ถูกต้อง สมมติว่ารันเป็นรูทเริ่มต้น จากนั้นจะมีลักษณะดังนี้:

#!/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
ฉันสงสัยว่าทำไมถึงไม่ได้คะแนนสูงกว่านี้ เป็นการแก้คำถามเดิมที่ดีที่สุดในขณะที่เก็บทุกอย่างไว้ในความสับสน
SirVer

หรือrunuser -u $user -- "$@"ตามที่ระบุไว้ใน su (1)
cghislai

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

1
ขอบคุณ @macieksk จับได้ดี จะอัพเดต. --เป็นประโยชน์จริงๆ
MarSoft

1
แนวทางที่นำเสนอเป็นสิ่งที่ดีที่สุดและสมบูรณ์ ทั้งหมดเขียนภายในสคริปต์เดียวและทั้งหมดใช้ bash สคริปต์นี้ถูกรันสองครั้งอย่างมีประสิทธิภาพ ในการทดสอบสคริปต์ครั้งแรกเป็น root จากนั้นเตรียมสภาพแวดล้อมและเปลี่ยนผู้ใช้โดย su แต่ทำด้วยคำสั่ง exec แล้วมีเพียงอินสแตนซ์สคริปต์เดียว ด้วยการวนซ้ำที่สองวลี if / fi เป็น ommited จากนั้นสคริปต์จะดำเนินการที่เตรียมไว้โดยตรง ในตัวอย่างนี้คือเสียงสะท้อน แนวทางอื่น ๆ ทั้งหมดแก้ไขปัญหาได้เพียงบางส่วน แน่นอนว่าสคริปต์นี้สามารถทำงานได้ภายใต้ sh not bash แต่เราต้องทดสอบตัวแปรพิเศษ $ HOME ไม่ใช่ $ UID
Znik

7

ใช้sudoแทน

แก้ไข : เป็นดักลาสชี้ว่าคุณไม่สามารถใช้cdในsudoเพราะมันไม่ได้เป็นภายนอกคำสั่ง คุณต้องรันคำสั่งใน subshell เพื่อให้cdทำงานได้

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

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

คุณอาจถูกขอให้ป้อนรหัสผ่านของผู้ใช้รายนั้น แต่เพียงครั้งเดียว


วิธีนี้จะใช้ไม่ได้ - cd จะหายไปหลังจาก sudo แรกดำเนินการเสร็จสิ้น
Douglas Leeder

อันที่จริงคุณไม่สามารถเรียก cd ได้โดยตรงเนื่องจากไม่ใช่คำสั่งภายนอก
iamamac

sudoอาจสะดวก แต่ก็ไม่ดีหากไม่ได้อยู่นอกกรอบ (เช่นบน AIX) su -c 'commands'คือคำตอบที่ถูกต้อง
หากิน

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 ตามที่เป็นไปได้ด้วย 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. หากคุณไม่ต้องการตัวแปรสภาพแวดล้อมให้ลบออก-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"
Charles Duffy

@CharlesDuffy คุณพูดถูก! ฉันปรับสคริปต์การผลิตของฉันให้เรียบง่ายมากเกินไปสำหรับคำตอบนี้ :-( เพียงแค่เพิ่มการCOMMANDARGS=$@แก้ปัญหาด้วย-cอาร์กิวเมนต์ที่มีช่องว่างไม่ได้เป็นปัญหามาก่อน แต่ฉันใช้อินพุตที่ดีของคุณฉันต้องทำการทดลองบางอย่างเพื่อให้มันทำงานได้ 'ได้แก้ไขคำถามแล้วและหวังว่าฉันจะไม่วางข้อผิดพลาดอื่นขอบคุณสำหรับความคิดเห็นของคุณน่าอับอาย แต่จำเป็น
Trendfischer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.