Làm cách nào để sử dụng su để thực thi phần còn lại của tập lệnh bash như người dùng đó?


126

Tôi đã viết một tập lệnh lấy, làm đối số, một chuỗi là nối của tên người dùng và dự án. Kịch bản được cho là chuyển (su) sang tên người dùng, cd sang một thư mục cụ thể dựa trên chuỗi dự án.

Về cơ bản tôi muốn làm:

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

Vấn đề là một khi tôi làm một su ... nó chỉ chờ ở đó. Điều này có ý nghĩa vì luồng thực thi đã được chuyển sang chuyển sang người dùng. Khi tôi thoát, phần còn lại của mọi thứ sẽ thực thi nhưng nó không hoạt động như mong muốn.

Tôi đã thêm su vào lệnh svn nhưng lệnh không thành công (nghĩa là nó không cập nhật svn trong thư mục mong muốn).

Làm cách nào để tôi viết một tập lệnh cho phép người dùng chuyển đổi người dùng và gọi svn (trong số những thứ khác)?

Câu trả lời:


86

Mẹo nhỏ là sử dụng lệnh "sudo" thay vì "su"

Bạn có thể cần phải thêm điều này

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

vào tập tin / etc / sudoers của bạn

và thay đổi tập lệnh của bạn thành:

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

Trong đó username2 là người dùng bạn muốn chạy lệnh SVN và username1 là người dùng đang chạy tập lệnh.

Nếu bạn cần nhiều người dùng để chạy tập lệnh này, hãy sử dụng %groupnamethay vì tên người dùng1


Tôi có một vấn đề tương tự, nhưng tôi muốn chạy chshcho những người dùng khác. Vấn đề của tôi được liệt kê ở đây tại stackoverflow.com/q/15307289/80353 Làm cách nào để điều chỉnh câu trả lời của bạn trong tình huống của tôi?
Kim Stacks

Tôi đã làm điều này - nhưng nó vẫn hỏi tôi mật khẩu.
Hippyjim

@Hippyjim bạn có chắc là bạn có tên người dùng đúng cách không?
Kimvais

1
Tôi đã làm - hóa ra tôi cũng cần phải cho phép sử dụng / bin / bash.
Hippyjim

3
Cho dù bạn sử dụng sudohoặc sucó tầm quan trọng thứ yếu, mặc dù sudoan toàn và thuận tiện hơn rất nhiều.
tripleee 24/2/2015

105

Đơn giản hơn nhiều: sử dụng sudođể chạy shell và sử dụng heredoc để cung cấp cho nó các lệnh.

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

(trả lời ban đầu trên SuperUser )


5
Câu trả lời này hoạt động tốt nhất. Tôi khuyên bạn nên sử dụng tùy chọn -iđể có được someusermôi trường mong đợi.
not2savvy

2
sudocó thể thuận tiện nhưng sẽ không tốt nếu nó không nằm ngoài hộp (như trên AIX). su -c 'commands'là câu trả lời đúng
Tricky

1
Giải pháp sử thi!
3bdalla

Làm thế nào để làm cho các biến có sẵn trong phạm vi của herdoc?
dotlashlu

trên AIX, nó ném lỗi này ksh: sh: 0403-006 Thực thi quyền bị từ chối.
AhmedRana

54

Sử dụng tập lệnh như sau để thực thi phần còn lại hoặc một phần của tập lệnh dưới một người dùng khác:

#!/bin/sh

id

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

id

eof

11
Bạn có thể muốn sử dụng "sudo -i -u ..." để đảm bảo rằng những thứ như $ HOME được đặt chính xác.
Bryan Larsen

Xin lỗi cho câu hỏi của Noob, nhưng id ở đây là gì?
Nitin Jadhav

1
@NitinJadhav, anh ấy đã sử dụng nó ở đây chỉ để hiển thị ID của người dùng hiện tại, ID gốc là 0, vì vậy id đầu tiên sẽ hiển thị cho bạn một số, nhưng cái thứ hai chắc chắn sẽ hiển thị 0 (vì cái thứ hai được thực thi bên trong một khối chạy bằng root). Bạn có thể sử dụng whoamithay vì idsẽ trả lại tên thay vì id
Mohammed Noureldin

@MohammedNoureldin Cảm ơn!
Nitin Jadhav

sudocó thể thuận tiện nhưng sẽ không tốt nếu nó không nằm ngoài hộp (như trên AIX). su -c 'commands'là câu trả lời đúng
Lừa

52

Bạn cần thực thi tất cả các lệnh người dùng khác nhau như tập lệnh riêng của họ. Nếu nó chỉ là một hoặc một vài lệnh, thì nội tuyến sẽ hoạt động. Nếu đó là nhiều lệnh thì có lẽ tốt nhất là chuyển chúng sang tệp riêng của chúng.

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

4
Đây là câu trả lời đúng duy nhất. Các sudo là không cần thiết cho việc này.
trực thăng

1
Bạn cũng có thể cần phải cung cấp vỏ với su -s /bin/bash.
mixel

giải pháp tốt nhất cho người dùng root
rfinz

Câu trả lời tốt nhất cho những người không cài đặt sudo theo mặc định (Tôi đang nhìn bạn AIX)
Tricky

46

Đây là một cách tiếp cận khác, thuận tiện hơn trong trường hợp của tôi (tôi chỉ muốn bỏ quyền root và thực hiện phần còn lại của tập lệnh từ người dùng bị hạn chế): bạn có thể làm cho tập lệnh tự khởi động lại từ người dùng chính xác. Hãy giả sử nó được chạy như root ban đầu. Sau đó, nó sẽ trông như thế này:

#!/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
Tôi tự hỏi tại sao điều này không được đánh giá cao hơn. Đó là giải quyết câu hỏi ban đầu tốt nhất trong khi giữ mọi thứ trong bash.
SirVer

Hoặc runuser -u $user -- "$@", như đã nêu trong su (1)
cghislai

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

1
Cảm ơn @macieksk, bắt tốt đẹp. Sẽ nâng cấp. Điều --này thực sự hữu ích.
MarSoft

1
Phương pháp trình bày là tốt nhất của tất cả và hoàn thành. Tất cả được viết bên trong tập lệnh đơn và tất cả đều sử dụng bash. Hiệu quả, kịch bản này được chạy hai lần. Đầu tiên kiểm tra kịch bản, nó là root, sau đó chuẩn bị môi trường và thay đổi người dùng bằng su. Nhưng làm điều đó với lệnh exec, thì chỉ có một thể hiện script duy nhất. Với vòng lặp thứ hai, cụm từ if / fi là ommited, sau đó script trực tiếp thực hiện hành động chuẩn bị. Trong ví dụ này là tiếng vang. Tất cả các phương pháp khác chỉ giải quyết vấn đề một phần. Tất nhiên tập lệnh này có thể được chạy theo sh không bash, nhưng chúng tôi phải kiểm tra biến đặc biệt $ HOME, không phải $ UID
Znik

7

Sử dụng sudothay thế

EDIT : Như Douglas chỉ ra, bạn không thể sử dụng cdtrong sudovì nó không phải là một bên ngoài lệnh. Bạn phải chạy các lệnh trong một subshell để thực hiện cdcông việc.

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

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

Bạn có thể được yêu cầu nhập mật khẩu của người dùng đó, nhưng chỉ một lần.


Tuy nhiên, điều đó sẽ không hoạt động - cd sẽ bị mất sau khi sudo đầu tiên hoàn thành.
Douglas Leeder

Trên thực tế, bạn thậm chí không thể gọi cd trực tiếp vì đó không phải là lệnh bên ngoài .
iamamac

sudocó thể thuận tiện nhưng sẽ không tốt nếu nó không nằm ngoài hộp (như trên AIX). su -c 'commands'là câu trả lời đúng
Tricky

6

Không thể thay đổi người dùng trong tập lệnh shell. Cách giải quyết bằng sudo được mô tả trong các câu trả lời khác có lẽ là đặt cược tốt nhất của bạn.

Nếu bạn đủ điên để chạy các tập lệnh perl với quyền root, bạn có thể thực hiện việc này với các $< $( $> $) biến chứa uid / gid thực / hiệu quả, ví dụ:

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

-1 như Nó thể với sudo để tạm thời đạt được các quyền khác của người dùng.
Kimvais

4
Theo nghĩa người dùng, kịch bản shell tự chạy là không thể thay đổi (đó là những gì câu hỏi ban đầu được hỏi). Gọi các tiến trình khác với sudo sẽ không thay đổi chính tập lệnh đang chạy.
P-Nuts

2

Điều này làm việc cho tôi

Tôi tách ra "cung cấp" của tôi từ "khởi động" của tôi.

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

sau đó trong start_env.sh của tôi

#!/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

Lấy cảm hứng từ ý tưởng từ @ MarSoft nhưng tôi đã thay đổi các dòng như sau:

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

Tôi đã sử dụng sudođể cho phép mật khẩu thực thi tập lệnh ít hơn. Nếu bạn muốn nhập mật khẩu cho người dùng, hãy xóa sudo. Nếu bạn không cần các biến môi trường, hãy loại bỏ-E khỏi sudo.

Việc /usr/bin/bash -lđảm bảo rằng các profile.dtập lệnh được thực thi cho một môi trường khởi tạo.


sudocó thể thuận tiện nhưng sẽ không tốt nếu nó không nằm ngoài hộp (như trên AIX). su -c 'commands'là câu trả lời đúng
Tricky

@Tricky Có lẽ đọc câu trả lời đầy đủ, nó đã gợi ý loại bỏ sudo. Trong thực tế, sudo không đơn giản như vậy, trong rất nhiều trường hợp bạn cần thậm chí sudo -Evà một mục cấu hình trong sudoers.d để cho phép thực thi mà không cần tty với !requiretty. Nhưng có rất nhiều trường hợp, trong đó sudo là cần thiết cho các tập lệnh được gọi tự động, trong đó một hộp thoại mật khẩu có thể can thiệp. Vì vậy, tôi sẽ không loại bỏ nó khỏi một giải pháp tiêu chuẩn.
Trendfischer 23/03/18

Mã trong câu hỏi là lỗi hoàn toàn - nó sẽ phá vỡ tên tập lệnh hoặc đối số có khoảng trắng; Hãy nhớ rằng việc đặt "$@"bên trong một chuỗi có nghĩa là các đối số vượt qua chuỗi đầu tiên được nối vào một chuỗi riêng biệt, không được bao gồm trong -cđối số. Nếu bạn muốn làm cho nó an toàn, bạn có thể printf -v arg_q '%q ' "$0" "$@"và sau đó sử dụngsu "$USERNAME" -c "/usr/bin/bash -l $arg_q"
Charles Duffy

@CharlesDuffy Bạn nói đúng! Tôi đã đơn giản hóa kịch bản sản xuất của mình quá nhiều cho câu trả lời này :-( Chỉ cần thêm một cách COMMANDARGS=$@giải quyết vấn đề với -c. Đối số với khoảng trắng không phải là vấn đề trước đây, nhưng tôi đã triển khai đầu vào tốt của bạn. Tôi chỉ phải thực hiện một số thử nghiệm để làm cho nó hoạt động. Tôi đã chỉnh sửa câu hỏi và hy vọng tôi không dán một lỗi khác. Cảm ơn vì nhận xét của bạn, nhục nhã nhưng cần thiết.
Trendfischer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.