สคริปต์ทุบตี: ผลลัพธ์ที่แตกต่างเมื่อเรียกด้วยหรือไม่ใช้ sudo


10

ใน Ubuntu 16.04.3 ฉันมีสคริปต์ทุบตีง่ายมาก:

test.sh

[[ 0 == 0 ]] && result="true" || result="false"
echo $result
echo $USER $SHELL $0

เมื่อฉันเรียกมันว่าเป็นผู้ใช้ที่ไม่ใช่รูทmeหรือrootทำงานได้ตามที่คาดไว้ ถ้าฉันใช้sudo ./test.shมันบ่นเกี่ยวกับข้อผิดพลาดทางไวยากรณ์:

$ ./test.sh
true
me /bin/bash ./test.sh

$ sudo su
# ./test.sh 
true
root /bin/bash ./test.sh

# exit
$ sudo ./test.sh
./test.sh: 1: ./test.sh: [[: not found
false
root /bin/bash ./test.sh

สิ่งที่อาจทำให้เกิดสิ่งนี้ ฉันจะแก้ไขได้อย่างไรเพื่อให้meสามารถใช้สคริปต์นี้ได้ตามปกติและด้วยsudo?


3
เคล็ดลับมือโปร: มีจุดใดในการทำงาน sudo suเพียงแค่เรียกใช้sudo -iหรือsudo -sแทน
terdon

@terdon เปลี่ยนตำแหน่งไปsudo -i หรือไม่เปลี่ยนตำแหน่งไดเรกทอรี /rootsudo susudo -s
James Newton

ใช่อ่านคำถามที่ฉันเชื่อมโยงไปก่อนหน้าแล้วเพราะเหตุใด -sและขอโทษฉันได้แก้ไขความคิดเห็นก่อนหน้าของฉันฉันได้ลืมที่จะกล่าวถึง
terdon

คำตอบ:


20

สคริปต์ทุกคนเริ่มต้นด้วยการshebangโดยไม่ได้เปลือกเริ่มต้นสคริปต์ของคุณไม่ทราบว่าควรใช้ล่ามของคุณสคริปต์1และยุทธ - ในกรณีของsudo ./script.shที่นี่ - วิ่งด้วยshซึ่งใน Ubuntu 16.04 dashจะเชื่อมโยงกับ นิพจน์เงื่อนไข [[เป็นbashคำสั่งสารประกอบจึงdashไม่ทราบวิธีจัดการกับมันและพ่นข้อผิดพลาดที่คุณพบ

ทางออกที่นี่คือการเพิ่ม

#!/bin/bash

เป็นบรรทัดแรกของสคริปต์ของคุณ คุณอาจได้รับผลลัพธ์เดียวกันเมื่อคุณเรียกมันอย่างชัดเจนด้วยsudo bash ./script.shแต่ Shebang เป็นวิธีที่จะไป
หากต้องการตรวจสอบว่าเชลล์ใดที่ใช้งานสคริปต์ของคุณให้เพิ่มลงecho $0ไป นั่นไม่เหมือนกับ echo $SHELLอ้างwiki.archlinux.org :

SHELL มีเส้นทางไปยังเชลล์ที่ต้องการของผู้ใช้ โปรดทราบว่านี่ไม่จำเป็นต้องเป็นเชลล์ที่กำลังทำงานอยู่แม้ว่า Bash จะตั้งค่าตัวแปรนี้เมื่อเริ่มต้น

1: ในขณะที่คุณเริ่มต้น./test.shด้วยbashมันเพิ่งสันนิษฐานbashไปเหมือนกันสำหรับsudo susubshell


1
นอกจากนี้ยังทราบทุบตีที่ทำงานสคริปต์โดยไม่ต้องใช้ shebang /bin/shทุบตีไม่
muru

@dessert ที่ช่วยแก้ไข ขอบคุณ! ฉันจะตรวจสอบจากภายในสคริปต์ที่เชลล์ใช้อยู่ได้อย่างไร? ( echo $0ให้ฉันชื่อของสคริปต์: ./test.sh)
เจมส์นิวตัน

@ JamesNewton ไม่มีวิธีพกพา AFAIK แต่คุณสามารถตรวจสอบสิ่งที่/proc/$$/exeชี้ไป นอกจากนี้คุณสามารถทดสอบตัวแปรต่างๆเช่น$BASH_VERSION, $ZSH_VERSIONฯลฯ ( แต่รีบไม่ได้ตั้งค่าใด ๆ ตัวแปรดังกล่าว)
Muru

5

ในฐานะที่เป็น@dessert อธิบายปัญหาที่นี่เป็นที่สคริปต์ของคุณไม่ได้มีสาย shebang โดยไม่ต้อง shebang ที่จะเริ่มต้นกับความพยายามที่จะเรียกใช้ไฟล์โดยใช้sudo /bin/shฉันไม่พบเอกสารใด ๆ เลย แต่ฉันยืนยันด้วยการตรวจสอบsudoซอร์สโค้ดที่ฉันพบสิ่งต่อไปนี้ในไฟล์pathnames.h:

#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
#endif /* _PATH_BSHELL */

ซึ่งหมายความว่า "ตั้งค่าหาก_PATH_BSHELLไม่ได้กำหนดตัวแปรตั้งเป็น/bin/sh" จากนั้นในconfigureสคริปต์ที่รวมอยู่ใน tarball แหล่งที่มาเรามี:

for p in "/bin/bash" "/usr/bin/sh" "/sbin/sh" "/usr/sbin/sh" "/bin/ksh" "/usr/bin/ksh" "/bin/bash" "/usr/bin/bash"; do
    if test -f "$p"; then
    found=yes
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $p" >&5
$as_echo "$p" >&6; }
    cat >>confdefs.h <<EOF
#define _PATH_BSHELL "$p"
EOF

    break
    fi
done

วงนี้จะมองหา/bin/bash, /usr/bin/sh, /sbin/sh, /usr/sbin/shหรือ/bin/kshแล้วชุด_PATH_BSHELLไปแล้วแต่จำนวนใดจะถูกค้นพบครั้งแรก เนื่องจาก/bin/shเป็นครั้งแรกในรายการและมันมีอยู่แล้วมีการตั้งค่า_PATH_BSHELL /bin/shผลลัพธ์ของสิ่งนี้คือเชลล์เริ่มต้นของsudoนอกจากจะกำหนดไว้เป็น/bin/shอย่างอื่น

ดังนั้นsudoจะเริ่มต้นกับการรันสิ่งต่าง ๆ ที่ใช้/bin/shและบน Ubuntu นั่นคือ symlink dashซึ่งเป็นเชลล์ที่สอดคล้องกับ POSIX น้อยที่สุด:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Feb 27  2015 /bin/sh -> dash

[[สร้างเป็นคุณลักษณะทุบตีมันไม่ได้ถูกกำหนดโดยมาตรฐาน POSIX และไม่เป็นที่เข้าใจโดยdash:

$ bash -c '[[ true ]] && echo yes'
yes
$ dash -c '[[ true ]] && echo yes'
dash: 1: [[: not found

ในรายละเอียดในการร้องขอทั้งสามที่คุณได้ลอง:

  1. ./test.sh

    ไม่sudo; ในกรณีที่ไม่มีบรรทัด Shebang เชลล์ของคุณจะพยายามเรียกใช้งานไฟล์เอง เมื่อคุณใช้งานbashสิ่งนี้จะทำงานbash ./test.shและทำงานอย่างมีประสิทธิภาพ

  2. sudo su./test.shตามมาด้วย

    rootที่นี่คุณจะเริ่มต้นเปลือกใหม่สำหรับผู้ใช้ นี่จะเป็นสิ่งที่เชลล์กำหนดไว้ใน$SHELLตัวแปรสภาพแวดล้อมสำหรับผู้ใช้นั้นและบน Ubuntu เชลล์เริ่มต้นของรูทคือbash:

    $ grep root /etc/passwd
    root:x:0:0:root:/root:/bin/bash
  3. sudo ./test.sh

    ที่นี่คุณจะปล่อยให้sudoรันคำสั่งโดยตรง ตั้งแต่เริ่มต้นเปลือกของมันจะถูก/bin/shตามที่อธิบายไว้ข้างต้นนี้ทำให้เกิดการเรียกใช้สคริปต์ด้วย/bin/shซึ่งเป็นdashและจะล้มเหลวเนื่องจากไม่เข้าใจdash[[


หมายเหตุ : รายละเอียดของวิธีการsudoตั้งค่าเปลือกเริ่มต้นดูเหมือนจะซับซ้อนกว่าเล็กน้อย ฉันพยายามเปลี่ยนไฟล์ที่กล่าวถึงในคำตอบของฉันให้ชี้ไปที่/bin/bashแต่sudoยังคงเป็นค่า/bin/shเริ่มต้น ดังนั้นจะต้องมีสถานที่อื่น ๆ ในซอร์สโค้ดที่เชลล์เริ่มต้นถูกกำหนดไว้ อย่างไรก็ตามประเด็นหลัก (ที่เป็นsudoค่าเริ่มต้นsh) ยังคงอยู่


ฉันไม่พบเอกสารที่ใดก็ได้ - ฉันไม่ฉันเพิ่งคิดว่ามันจะใช้/bin/shจากข้อความแสดงข้อผิดพลาด - มีอะไรอีกบ้างที่เป็นไปได้? คำถามคือตอบอย่างสวยงามในสิ่งที่เปลือกไม่ใช้ sudo · SOเห็นการดำเนินการในส่วนคำสั่งman sudo ปรากฎsudoว่าไม่ได้ใช้เปลือกกลาง !
ของหวาน

1
@dessert ใช่มันใช้การดำเนินการของตัวเองเรียกระบบที่เริ่มต้นที่execve shและไม่เชลล์ระดับกลางไม่เกี่ยวข้องนี่ไม่เกี่ยวกับเชลล์ที่รันคำสั่ง แต่เกี่ยวกับเชลล์ interpreter ที่ใช้ในการอ่านเชลล์สคริปต์ที่กำหนด ไม่เลยมันไม่เปิดตัวเชลล์ระดับกลาง แต่ก็ยังต้องการตัวแปลเชลล์สำหรับเชลล์สคริปต์
terdon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.