Cách giữ biến môi trường khi sử dụng sudo


425

Khi tôi sử dụng bất kỳ lệnh nào với sudo, các biến môi trường không có ở đó. Ví dụ: sau khi đặt HTTP_PROXY, lệnh wgethoạt động tốt mà không có sudo. Tuy nhiên nếu tôi gõ sudo wgetthì nó báo không thể bỏ qua cài đặt proxy.



Câu trả lời:


475

Đầu tiên bạn cần phải export HTTP_PROXY. Thứ hai, bạn cần đọc man sudokỹ, và chú ý đến -Ecờ. Những công việc này:

$ export HTTP_PROXY=foof
$ sudo -E bash -c 'echo $HTTP_PROXY'

Đây là trích dẫn từ trang người đàn ông:

-E, --preserve-env
             Indicates to the security policy that the user wishes to preserve their
             existing environment variables.  The security policy may return an error
             if the user does not have permission to preserve the environment.

1
vấn đề lớn duy nhất là sửa đổi một số tệp cấu hình, ví dụ pacman cho vòm để làm cho -E được thông qua
Ahmed Aswani

7
Để cho phép -E (bảo vệ môi trường) cho wget, bạn cần chỉ định thẻ SETENV trên quy tắc sudo cho phép chạy wget - Ví dụ: <username> ALL = (root) NOPASSWD: SETENV: <path to wget>
John Bowers

65
"-E" này không hoạt động nếu biến là PATH hoặc PYTHONPATH.
apporc

Cũng không hoạt động với bất kỳ LC_*biến. Vì vậy, chỉ cần làm export LOL_FOO=$LC_FOOvà sử dụng LOL_FOOthay thế.
luckydonald

9
Điều này không hoạt động với trường hợp đơn giản hơn là thêm một phần tử PATHvào .bashrctệp - giả sử , export PATH=myPath:$PATH. Nếu tôi gõ sudo -E bash -c 'echo $PATH', thì PATHkhông chứa myPath có lẽ vì sudođã vô hiệu hóa giá trị cục bộ PATHtrước khi gọi bash. Thay vào đó, tôi đã tìm thấy câu trả lời bên dưới stackoverflow.com/a/33183620/5459638 có hiệu lực, đó làsudo PATH=$PATH command
XavierStuvw

310

Mẹo nhỏ là thêm các biến môi trường vào sudoerstệp thông qua sudo visudolệnh và thêm các dòng sau:

Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy"

lấy từ wiki ArchLinux .

Đối với Ubuntu 14, bạn cần chỉ định trong các dòng riêng biệt vì nó trả về lỗi cho các dòng đa biến:

Defaults  env_keep += "http_proxy"
Defaults  env_keep += "https_proxy"
Defaults  env_keep += "HTTP_PROXY"
Defaults  env_keep += "HTTPS_PROXY"

11
Đây được cho là lựa chọn tốt nhất, để tránh rò rỉ thông tin và lỗ hổng bảo mật. sudo -Elà cách chắc chắn để adhoc có được hiệu quả tương tự cho một lần, mặc dù vậy
sehe

Tôi gặp phải vấn đề của một quá trình là người gọi sudo (jhbuild) và tôi không thể bảo nó chuyển cờ -E sang sudo, vì vậy đây là giải pháp của tôi.
jgomo3

60
Lưu ý rằng bạn không bao giờ nên chỉnh sửa etc/sudoerstrực tiếp. Thay vào đó, hãy sử dụng visudolệnh kiểm tra cú pháp của bạn trước khi ghi đè sudoerstệp. Bằng cách đó, bạn không tự khóa nếu bạn mắc lỗi trong khi chỉnh sửa.
Henning

1
Xem xét sử dụng vars env chữ hoa. Trong trường hợp của tôi, việc sử dụng HTTP_PROXY và HTTPS_PROXY đã thực hiện thủ thuật này.
pabo

2
biến thể chữ thường là tốt hơn từ kinh nghiệm của tôi vì nó hoạt động trong cả wget và curl.
Miroslav Mộcek

57

Đối với các biến riêng lẻ bạn muốn cung cấp trên cơ sở một lần, bạn có thể biến nó thành một phần của lệnh.

sudo http_proxy=$http_proxy wget "http://stackoverflow.com"

Tôi đã kiểm tra câu trả lời này cho một packagesố myPath được thêm vào PATHtrong .bashrctệp (với exportmệnh đề). Sau đó sudo PATH=$PATH which packagetìm câu trả lời đúng, không giống như sudo which package. Tuy nhiên, sudo PATH=$PATH packagekhông đi xa hơn sudo package(không tìm thấy tệp). Mặt khác, khởi động một đồng bằng packagetừ một chiếc vỏ được gọi với sudo bashbảo tồn con đường mở rộng và trao packagequyền sudo (hai con chim bồ câu với một viên đá). Vì vậy, phản hồi thực sự phụ thuộc vào lệnh bạn đang khởi chạy
XavierStuvw

2
Độ phân giải PATH cho sudo là một vấn đề khác - bất cứ ai nên tìm bài này trong tìm kiếm của vấn đề đó tôi khuyên bạn nên xem unix.stackexchange.com/questions/83191/...
buckaroo1177125

24

Bạn cũng có thể kết hợp hai env_keepcâu trong câu trả lời của Ahmed Aswani thành một câu như sau:

Defaults env_keep += "http_proxy https_proxy"

Bạn cũng nên xem xét chỉ định env_keepcho một lệnh duy nhất như thế này:

Defaults!/bin/[your_command] env_keep += "http_proxy https_proxy"


1

Hàm bao bọc đơn giản (hoặc trong dòng cho vòng lặp)

Tôi đã đưa ra một giải pháp độc đáo bởi vì:

  • sudo -E "$@" đã rò rỉ các biến gây ra vấn đề cho lệnh của tôi
  • sudo VAR1="$VAR1" ... VAR42="$VAR42" "$@" dài và xấu trong trường hợp của tôi

demo.sh

#!/bin/bash

function sudo_exports(){
    eval sudo $(for x in $_EXPORTS; do printf '%q=%q ' "$x" "${!x}"; done;) "$@"
}

# create a test script to call as sudo
echo 'echo Forty-Two is $VAR42' > sudo_test.sh
chmod +x sudo_test.sh

export VAR42="The Answer to the Ultimate Question of Life, The Universe, and Everything."

export _EXPORTS="_EXPORTS VAR1 VAR2 VAR3 VAR4 VAR5 VAR6 VAR7 VAR8 VAR9 VAR10 VAR11 VAR12 VAR13 VAR14 VAR15 VAR16 VAR17 VAR18 VAR19 VAR20 VAR21 VAR22 VAR23 VAR24 VAR25 VAR26 VAR27 VAR28 VAR29 VAR30 VAR31 VAR32 VAR33 VAR34 VAR35 VAR36 VAR37 VAR38 VAR39 VAR40 VAR41 VAR42"

# clean function style
sudo_exports ./sudo_test.sh

# or just use the content of the function
eval sudo $(for x in $_EXPORTS; do printf '%q=%q ' "$x" "${!x}"; done;) ./sudo_test.sh

Kết quả

$ ./demo.sh
Forty-Two is The Answer to the Ultimate Question of Life, The Universe, and Everything.
Forty-Two is The Answer to the Ultimate Question of Life, The Universe, and Everything.

Làm sao?

Điều này được thực hiện bởi một tính năng của nội dung bash printf. Việc %qtạo ra một chuỗi trích dẫn shell. Không giống như mở rộng tham số trong bash 4.4 , điều này hoạt động trong các phiên bản bash <4.0


0

Nếu bạn có nhu cầu giữ các biến môi trường trong một tập lệnh, bạn có thể đặt lệnh của bạn trong một tài liệu ở đây như thế này. Đặc biệt là nếu bạn có nhiều biến để thiết lập mọi thứ trông gọn gàng theo cách này.

# prepare a script e.g. for running maven
runmaven=/tmp/runmaven$$
# create the script with a here document 
cat << EOF > $runmaven
#!/bin/bash
# run the maven clean with environment variables set
export ANT_HOME=/usr/share/ant
export MAKEFLAGS=-j4
mvn clean install
EOF
# make the script executable
chmod +x $runmaven
# run it
sudo $runmaven
# remove it or comment out to keep
rm $runmaven
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.