วิธีเก็บตัวแปรสภาพแวดล้อมเมื่อใช้ sudo


425

เมื่อฉันใช้คำสั่งใด ๆ กับ sudo ตัวแปรสภาพแวดล้อมจะไม่อยู่ที่นั่น ยกตัวอย่างเช่นหลังจากการตั้งค่า http_proxy คำสั่งปรับการทำงานได้โดยไม่ต้องwget sudoอย่างไรก็ตามถ้าฉันพิมพ์sudo wgetมันบอกว่ามันไม่สามารถข้ามการตั้งค่าพร็อกซี



คำตอบ:


475

export HTTP_PROXYแรกที่คุณต้อง ประการที่สองคุณต้องอ่านman sudoอย่างระมัดระวังและใส่ใจกับ-Eธง งานนี้:

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

นี่คือคำพูดจากหน้าคน:

-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
ยอดเยี่ยมปัญหาเดียวที่แก้ไขไฟล์กำหนดค่าบางอย่างเช่น pacman สำหรับ arch เพื่อให้ -E ผ่านไปแล้ว
Ahmed Aswani

7
ในการอนุญาตให้ -E (รักษาสภาพแวดล้อม) สำหรับ wget คุณต้องระบุแท็ก SETENV บนกฎ sudo ที่อนุญาตให้เรียกใช้ wget - ตัวอย่าง: <username> ALL = (root) NOPASSWD: SETENV: <พา ธ ไปที่ wget>
John Bowers

66
"-E" นี้ใช้ไม่ได้หากตัวแปรคือ PATH หรือ PYTHONPATH
apporc

ยังไม่ทำงานกับLC_*ตัวแปรใด ๆ ดังนั้นเพียงทำexport LOL_FOO=$LC_FOOและใช้LOL_FOOแทน
luckydonald

9
เรื่องนี้ไม่ได้ทำงานกับกรณีที่เรียบง่ายของการเพิ่มองค์ประกอบหนึ่งไปPATHใน.bashrcไฟล์ - export PATH=myPath:$PATHพูด ถ้าผมพิมพ์sudo -E bash -c 'echo $PATH'แล้วPATHไม่ได้มี mypath อาจจะเป็นเพราะsudoได้ปิดใช้งานแล้วคุ้มค่าในท้องถิ่นของก่อนที่จะเรียกPATH bashแต่ฉันพบคำตอบด้านล่างstackoverflow.com/a/33183620/5459638มีประสิทธิภาพนั่นคือsudo PATH=$PATH command
XavierStuvw

310

เคล็ดลับคือการเพิ่มตัวแปรสภาพแวดล้อมลงในsudoersไฟล์ผ่านsudo visudoคำสั่งและเพิ่มบรรทัดเหล่านี้:

Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy"

นำมาจากArchLinux วิกิพีเดีย

สำหรับ Ubuntu 14 คุณจะต้องระบุเป็นบรรทัดแยกกันเนื่องจากมันจะส่งคืนข้อผิดพลาดสำหรับบรรทัดที่มีหลายตัวแปร:

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

11
นี่เป็นตัวเลือกที่ดีที่สุดในการหลีกเลี่ยงการรั่วไหลของข้อมูลและช่องโหว่ด้านความปลอดภัย sudo -Eเป็นวิธีที่แน่นอนในการ adhoc ได้รับผลเหมือนกันสำหรับ one-off แม้ว่า
sehe

ฉันพบปัญหาของกระบวนการที่เป็นคนที่เรียก sudo (jhbuild) และฉันไม่สามารถบอกให้ส่งแฟล็ก -E ไปยัง sudo ได้นี่เป็นวิธีแก้ปัญหาของฉัน
jgomo3

61
ขอให้สังเกตว่าคุณไม่ควรแก้ไขetc/sudoersโดยตรง ให้ใช้visudoคำสั่งซึ่งจะตรวจสอบการแก้ไขของคุณก่อนเขียนทับsudoersไฟล์แทน ด้วยวิธีนี้คุณจะไม่ล็อคตัวเองถ้าคุณทำผิดพลาดขณะแก้ไข
Henning

1
พิจารณาใช้ตัวพิมพ์ใหญ่ env vars ในกรณีของฉันการใช้ HTTP_PROXY และ HTTPS_PROXY ทำเคล็ดลับ
pabo

2
ตัวพิมพ์เล็กนั้นดีกว่าจากประสบการณ์ของฉันเพราะมันใช้ได้ทั้งใน wget และ curl
Miroslav Mocek

57

สำหรับตัวแปรแต่ละตัวที่คุณต้องการทำให้พร้อมใช้งานในครั้งเดียวคุณสามารถทำให้มันเป็นส่วนหนึ่งของคำสั่ง

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

ฉันได้ทดสอบคำตอบนี้packageภายใต้ myPath บางส่วนที่เพิ่มลงPATHใน.bashrcไฟล์ (มีส่วนคำexportสั่ง) จากนั้นsudo PATH=$PATH which packageหาคำตอบที่ถูกต้องไม่เหมือนsudo which packageกัน อย่างไรก็ตามsudo PATH=$PATH packageไม่ไปไกลกว่านี้sudo package(ไม่พบไฟล์) ในอีกทางหนึ่งการยิงpackageกระสุนธรรมดาจากเปลือกหอยที่มีการsudo bashรักษาเส้นทางขยายและให้packageสิทธิ์ sudo (นกพิราบสองตัวที่มีหินก้อนเดียว) ดังนั้นการตอบสนองขึ้นอยู่กับคำสั่งที่คุณกำลังเปิดตัว
XavierStuvw

2
ความละเอียดเส้นทางสำหรับ sudo เป็นอีกเรื่องหนึ่ง - ทุกคนควรจะหาโพสต์นี้ในการค้นหาของเรื่องที่ผมขอแนะนำให้เห็นunix.stackexchange.com/questions/83191/...
buckaroo1177125

24

คุณสามารถรวมทั้งสองenv_keepข้อความในคำตอบของ Ahmed Aswani เป็นคำเดียวเช่นนี้:

Defaults env_keep += "http_proxy https_proxy"

คุณควรพิจารณาระบุenv_keepเพียงคำสั่งเดียวเช่นนี้:

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


1

ฟังก์ชั่น wrapper ง่าย ๆ (หรืออินไลน์สำหรับการวนซ้ำ)

ฉันคิดวิธีแก้ปัญหาเฉพาะขึ้นมาเพราะ:

  • sudo -E "$@" กำลังรั่วตัวแปรที่ทำให้เกิดปัญหากับคำสั่งของฉัน
  • sudo VAR1="$VAR1" ... VAR42="$VAR42" "$@" ยาวและน่าเกลียดในกรณีของฉัน

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

ผลลัพธ์

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

อย่างไร?

นี้ทำไปได้โดยคุณลักษณะของ printfbuiltin %qผลิตสตริงเปลือกที่ยกมา ซึ่งแตกต่างจากการขยายพารามิเตอร์ใน bash 4.4ซึ่งทำงานใน bash เวอร์ชัน <4.0


0

หากคุณมีความต้องการที่จะเก็บตัวแปรสภาพแวดล้อมในสคริปต์คุณสามารถใส่คำสั่งของคุณในเอกสารที่นี่เช่นนี้ โดยเฉพาะถ้าคุณมีตัวแปรมากมายที่จะทำให้สิ่งต่าง ๆ ดูเป็นระเบียบเรียบร้อย

# 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.