Cara menjaga variabel lingkungan saat menggunakan sudo


425

Ketika saya menggunakan perintah apa pun dengan sudo, variabel lingkungan tidak ada. Misalnya setelah mengatur HTTP_PROXY, perintah tersebut wgetberfungsi dengan baik tanpa sudo. Namun jika saya mengetiknya sudo wgetdikatakan tidak bisa melewati pengaturan proxy.



Jawaban:


475

Pertama, Anda perlu export HTTP_PROXY. Kedua, Anda perlu membaca man sudodengan cermat, dan memperhatikan -Ebenderanya. Ini bekerja:

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

Ini kutipan dari halaman manual:

-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
hebat satu-satunya masalah yang memodifikasi beberapa file konfigurasi misalnya pacman untuk lengkungan untuk membuat -E disahkan
Ahmed Aswani

7
Untuk mengizinkan -E (menjaga lingkungan) untuk wget, Anda perlu menentukan tag SETENV pada aturan sudo yang memungkinkan jalannya wget - Contoh: <username> ALL = (root) NOPASSWD: SETENV: <path to wget>
John Bowers

66
"-E" ini tidak berfungsi jika variabelnya PATH atau PYTHONPATH.
apporc

Juga tidak berfungsi dengan LC_*variabel apa pun . Jadi lakukan saja export LOL_FOO=$LC_FOOdan gunakan LOL_FOOsaja.
luckydonald

9
Ini tidak bekerja dengan kasus sederhana menambahkan satu elemen ke PATHdalam .bashrcfile - katakanlah export PATH=myPath:$PATH,. Jika saya mengetik sudo -E bash -c 'echo $PATH', maka PATHtidak mengandung myPath mungkin karena sudotelah menonaktifkan nilai lokal PATHsebelum memanggil bash. Sebaliknya, saya menemukan jawaban di bawah ini stackoverflow.com/a/33183620/5459638 efektif, yaitusudo PATH=$PATH command
XavierStuvw

310

Caranya adalah dengan menambahkan variabel lingkungan ke sudoersfile melalui sudo visudoperintah dan tambahkan baris ini:

Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy"

diambil dari ArchLinux wiki .

Untuk Ubuntu 14, Anda perlu menentukan dalam baris terpisah karena mengembalikan kesalahan untuk baris multi-variabel:

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

11
Ini bisa dibilang pilihan terbaik, untuk menghindari kebocoran informasi dan lubang keamanan. sudo -Eadalah cara yang pasti-api untuk adhoc mendapatkan efek yang sama untuk satu-off, meskipun
sehe

Saya mengalami masalah dalam proses menjadi orang yang memanggil sudo (jhbuild) dan saya tidak bisa mengatakannya untuk meneruskan flag -E ke sudo, jadi ini solusi saya.
jgomo3

61
Perhatikan bahwa Anda tidak boleh mengedit etc/sudoerssecara langsung. Sebagai gantinya, gunakan visudoperintah, yang memeriksa sintaks Anda sebelum menimpa sudoersfile. Dengan begitu, Anda tidak mengunci diri jika Anda melakukan kesalahan saat mengedit.
Henning

1
Pertimbangkan untuk menggunakan vars huruf besar. Dalam kasus saya, penggunaan HTTP_PROXY dan HTTPS_PROXY berhasil.
pabo

2
varian huruf kecil lebih baik dari pengalaman saya karena berfungsi baik di wget dan curl.
Miroslav Mocek

57

Untuk variabel individual yang ingin Anda sediakan satu per satu, Anda dapat menjadikannya bagian dari perintah.

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

Saya telah menguji jawaban ini untuk packagebeberapa myPath di bawah ditambahkan ke PATHdalam .bashrcfile (dengan exportklausul). Kemudian sudo PATH=$PATH which packagetemukan jawaban yang benar, tidak seperti sudo which package. Namun, sudo PATH=$PATH packagetidak melangkah lebih jauh dari sudo package(file tidak ditemukan). Di sisi lain, meluncurkan dataran packagedari shell yang digunakan untuk sudo bashmempertahankan jalur yang panjang dan memberikan packagehak sudo (dua merpati dengan satu batu). Jadi responsnya sangat tergantung pada perintah mana yang Anda luncurkan
XavierStuvw

2
Resolusi PATH untuk sudo adalah masalah lain - siapa pun dapat menemukan posting ini dalam mencari masalah yang saya sarankan melihat unix.stackexchange.com/questions/83191/…
buckaroo1177125

24

Anda juga dapat menggabungkan dua env_keeppernyataan dalam jawaban Ahmed Aswani menjadi satu pernyataan seperti ini:

Defaults env_keep += "http_proxy https_proxy"

Anda juga harus mempertimbangkan env_keepuntuk menentukan hanya satu perintah seperti ini:

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


1

Fungsi pembungkus sederhana (atau in-line untuk loop)

Saya datang dengan solusi unik karena:

  • sudo -E "$@" bocor variabel yang menyebabkan masalah untuk perintah saya
  • sudo VAR1="$VAR1" ... VAR42="$VAR42" "$@" panjang dan jelek dalam kasus saya

dem. 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

Hasil

$ ./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.

Bagaimana?

Ini dimungkinkan oleh fitur bash builtin printf. The %qmenghasilkan shell string dikutip. Berbeda dengan ekspansi parameter di bash 4.4 , ini bekerja di versi bash <4.0


0

Jika Anda memiliki kebutuhan untuk menjaga variabel lingkungan dalam skrip Anda dapat menempatkan perintah Anda dalam dokumen di sini seperti ini. Terutama jika Anda memiliki banyak variabel untuk mengatur hal-hal terlihat rapi dengan cara ini.

# 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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.