ฉันได้ประกาศฟังก์ชั่นและตัวแปรใน bash / ksh และฉันต้องการส่งต่อไปยังsudo su - {user} << EOF:
#!/bin/bash
log_f() {
echo "LOG line: $@"
}
extVAR="yourName"
sudo su - <user> << EOF
intVAR=$(date)
log_f ${intVAR} ${extVAR}
EOF
ฉันได้ประกาศฟังก์ชั่นและตัวแปรใน bash / ksh และฉันต้องการส่งต่อไปยังsudo su - {user} << EOF:
#!/bin/bash
log_f() {
echo "LOG line: $@"
}
extVAR="yourName"
sudo su - <user> << EOF
intVAR=$(date)
log_f ${intVAR} ${extVAR}
EOF
คำตอบ:
sudo su -ซึ่งเป็นวิธีที่ซับซ้อนในการเขียนsudo -iสร้างสภาพแวดล้อมที่เก่าแก่ นั่นคือจุดของเปลือกเข้าสู่ระบบ แม้แต่ธรรมดาsudoจะลบตัวแปรส่วนใหญ่ออกจากสภาพแวดล้อม นอกจากนี้ยังsudoเป็นคำสั่งจากภายนอก ไม่มีวิธีในการยกระดับสิทธิ์ในเชลล์สคริปต์เท่านั้นเพื่อรันโปรแกรมภายนอก ( sudo) ด้วยสิทธิ์พิเศษและนั่นหมายถึงตัวแปรเชลล์ใด ๆ (เช่นตัวแปรที่ไม่ได้ถูกเอ็กซ์พอร์ต) และฟังก์ชั่นที่กำหนดในพาเรนต์เชลล์จะไม่สามารถใช้ได้ เปลือกลูก
คุณสามารถส่งผ่านตัวแปรสภาพแวดล้อมโดยไม่ต้องเรียกใช้เชลล์ล็อกอิน ( sudo bashแทนsudo su -หรือsudo -i) และกำหนดค่า sudo เพื่อให้ตัวแปรเหล่านี้ผ่าน (ด้วยDefaults !env_resetหรือDefaults env_keep=…ในsudoersไฟล์) สิ่งนี้จะไม่ช่วยคุณในการใช้งานฟังก์ชั่น (แม้ว่า bash จะมีฟังก์ชั่นการส่งออกฟังก์ชั่น sudo จะบล็อกมัน)
วิธีปกติในการรับฟังก์ชั่นของคุณในเปลือกลูกก็คือการกำหนดไว้ที่นั่น ดูแลข้อความ: ถ้าคุณใช้<<EOFเอกสาร here เนื้อหาของเอกสาร here จะถูกขยายก่อนโดย parent shell และผลลัพธ์ของการขยายตัวนั้นจะกลายเป็นสคริปต์ที่ child shell มองเห็น นั่นคือถ้าคุณเขียน
sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
สิ่งนี้แสดงชื่อของผู้ใช้ดั้งเดิมไม่ใช่ผู้ใช้เป้าหมาย เพื่อหลีกเลี่ยงการขยายระยะแรกให้อ้างเครื่องหมายเอกสารที่นี่หลังจาก<<ผู้ดำเนินการ:
sudo -u "$target_user" -i <<'EOF'
echo "$(whoami)"
EOF
ดังนั้นหากคุณไม่ต้องการส่งผ่านข้อมูลจากพาเรนต์เชลล์ไปยัง child shell คุณสามารถใช้เอกสารที่ยกมาที่นี่:
#!/bin/bash
sudo -u "$target_user" -i <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}"
EOF
ในขณะที่คุณสามารถใช้เครื่องหมายของเอกสารที่ไม่ได้ยกมาที่นี่เพื่อส่งผ่านข้อมูลจากพาเรนต์เชลล์ไปยังเชลล์ลูก แต่จะใช้ได้เฉพาะในกรณีที่ข้อมูลไม่มีอักขระพิเศษใด ๆ นั่นเป็นเพราะในสคริปต์เช่น
sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
ผลลัพธ์ของการwhoamiเป็นบิตของรหัสเปลือกไม่ใช่สตริง ตัวอย่างเช่นถ้าwhoamiคำสั่งกลับมาแล้วเปลือกเด็กจะรันคำสั่ง"; rm -rf /; "trueecho ""; rm -rf /; "true"
หากคุณต้องการส่งผ่านข้อมูลจากพาเรนต์เชลล์วิธีง่ายๆคือส่งผ่านเป็นอาร์กิวเมนต์ เรียกใช้เปลือกลูกอย่างชัดเจนและส่งผ่านพารามิเตอร์ตำแหน่ง:
#!/bin/bash
extVAR="yourName"
sudo -u "$target_user" -i sh _ "$extVAR" <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}" "${1}"
EOF
หากคุณมีตัวแปรหลายตัวที่จะผ่านมันจะสามารถอ่านได้ง่ายกว่าในการตั้งชื่อตัวแปร โทรenvอย่างชัดเจนเพื่อตั้งค่าตัวแปรสภาพแวดล้อมสำหรับเปลือกเด็ก
#!/bin/bash
extVAR="yourName"
sudo -u "$target_user" -i env extVAR="$extVAR" sh <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}" "${1}"
EOF
โปรดทราบว่าถ้าคุณคาดหวัง/etc/profileและผู้ใช้เป้าหมายคือ~/.profileจะอ่านคุณจะต้องอ่านพวกเขาอย่างชัดเจนหรือโทรแทนbash --loginsh
สิ่งนี้ไม่ทำงานเนื่องจากฟังก์ชั่นlog_fไม่ได้ประกาศในsudo su -เชลล์ที่คุณเปิดใช้ แทน:
extVAR="yourName"
sudo su - <user> << EOF
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f ${intVAR} ${extVAR}
EOF
คุณต้องรับฟังก์ชั่นที่กำหนดในรูตย่อยของรูท อาจทำได้ แต่ .... ฉันไม่รู้ว่าส่วนใหญ่ของสิ่งนั้นทำอะไร อย่างน้อย - ตราบใดที่ค่าsudoมิได้suความต้องการ stdin อ่านรหัสผ่าน - ที่ควรจะได้รับlog_f()การประกาศ
ฉันเชื่อว่าคุณหมายถึงการขยายค่าเหล่านั้นไปยังอินพุตของรูทเชลล์โดยวิธีการ หากคุณไม่ได้ตั้งใจที่จะทำเช่นนั้นคุณควรพูดEOFและ vars ด้วยตนเอง
ในกรณีของฉันฉันต้องการที่จะผ่านอาร์เรย์และมีปัญหาบางอย่าง แต่ก็ประสบความสำเร็จหลังจากที่ในขณะโดยสะท้อนค่าอาร์เรย์ไปยังenv-key และห่อรหัสตั้งใจในและพื้นมีมันสร้างอาร์เรย์เช่นbash -c '<intended code>' .:INNER_KEY=($<env_key>)
สำหรับการสอบ:
#!/usr/bin/env bash
PLUGINS=(foo bar baz)
sudo -u <some-user> -i env PLUGINS="`echo ${PLUGINS[@]}`" sh <<'EOF'
bash -c '
FOO=($PLUGINS);
echo values: \[${FOO[@]}\];
for pl in ${FOO[@]};
do echo value: $pl;
done;
'
EOF
ปัญหาคือฉันไม่สามารถทำสิ่งต่อไปนี้โดยตรง (ไม่ได้ใช้bash -c '...'):
FOO=($PLUGINS);
for pl in ${FOO[@]};
...