สคริปต์ของฉันจะกำหนดได้อย่างไรว่ามันถูกเรียกใช้โดย bash หรือ dash หรือไม่


13

ฉันกำลังใช้การติดตั้ง Oneiric ใหม่ (เช่นไม่ใช่การอัปเกรด) บนระบบที่แตกต่างกันสองระบบและทำงานในปัญหาเดียวกันที่เกี่ยวข้อง

พวงที่น่าผิดหวังที่สุดคือเมื่อฉันใช้. profile และ. bashrc ที่ฉันพกติดตัวไปด้วยจาก Mac OS X การเข้าสู่ X ผ่าน LightDM จะทำให้ฉันออกจากระบบทันที ฉันเชื่อว่าสิ่งนี้เกิดจากความจริงที่ว่าเมื่อรัน "/ bin / sh" มันจะทำงานเป็น / bin / dash แต่ยังคงมีตัวแปร $ SHELL ตั้งเป็น / bin / bash

การคาดการณ์

.bashrcฉันมีขนาดใหญ่ คุณสามารถดูได้ที่นี่หากคุณต้องการ แต่เนื้อหาอาจไม่เกี่ยวข้องนอกเหนือจากข้อเท็จจริงที่ว่ามันเต็มไปด้วย bashisms และความจริงที่ว่ามันทำงานได้โดยไม่มีข้อผิดพลาดภายใน xterm หรือบนคอนโซลเสมือน

.profileหน้าตาของฉันแบบนี้ (ตัวย่อ):

case $SHELL in 
*bash*)
    if [ -f $HOME/.bashrc -a -r $HOME/.bashrc ]; then
        . $HOME/.bashrc
    fi
    ;;
esac

หากฉันพยายามเข้าสู่ X ผ่าน LightDM มันจะเข้าสู่ระบบของฉันทันทีที่ออกจากระบบ ฉันพบข้อผิดพลาด.xsession-errorsเกี่ยวกับ. bashrc ของฉันที่มีลักษณะเช่นนี้ (ตัวย่อ):

/home/mrled/.bashrc: 103: [[: not found
[: 103: Linux: unexpected operator
[: 274: -P :: unexpected operator
/home/mrled/.bashrc: 520: complete: not found

อย่างที่ฉันพูดเมื่อฉันเรียกใช้ bash จากคอนโซลเสมือนฉันไม่ได้รับข้อผิดพลาดเหล่านี้ นอกจากนี้หากฉันลบ. profile ของฉันฉันสามารถเข้าสู่ X ได้ดี (ฉันยังสามารถเข้าสู่คอนโซลเสมือนและใช้startxเพื่อเริ่มต้นเซสชัน X ที่ใช้งานได้ แต่นี่ไม่ใช่วิธีการแก้ปัญหาระยะยาว)

อย่างไรก็ตามฉันค้นพบว่าถ้าฉันวิ่ง/bin/sh -lฉันจะได้รับข้อผิดพลาด ต่อไปนี้เป็นตัวอย่างเซสชัน (หมายเหตุ: bash prompt ที่ฉันทำง่ายbash>ขึ้นและ sh prompt เป็นเพียง$):

bash> echo $SHELL
/bin/bash
bash> echo $BASH_VERSION
4.2.10(1)-release
bash> /bin/sh -l
/home/mrled/.bashrc: 103: [[: not found
[: 103: Linux: unexpected operator
[: 274: -P :: unexpected operator
/home/mrled/.bashrc: 520: complete: not found
$ echo $SHELL
/bin/bash
$ echo $BASH_VERSION

$

Q1: ทำไมสิ่งนี้จึงเกิดขึ้น

ฉันเข้าใจว่า/ bin / sh ชี้ไปที่การประมากกว่าการทุบตีแต่ถ้าเป็นจริงแล้วทำไม$SHELLยังคงกลับมา/bin/bash?

Q2: ฉันจะแก้ไขปัญหานี้ได้อย่างไร

มีวิธีแก้ไขไหม ฉันต้องการเก็บโปรไฟล์ของฉันไว้. bashrc เพื่อให้ฉันได้รับสภาพแวดล้อมเดียวกันทั้งในการเข้าสู่ระบบและที่ไม่ใช่การเข้าสู่ระบบเปลือกหอย แต่เห็นได้ชัดว่าฉันต้องการให้โหลดเพื่อทุบตีเท่านั้นไม่ใช่ / bin / sh masquerading

คุณอาจสังเกตเห็นความแตกต่างในเนื้อหาของตัวแปร $ BASH_VERSION ด้านบน ฉันได้ลองห่อ. profile ในบางสิ่งเช่นนี้แล้ว:

if [ -n $BASH_VERSION ]; then
    # the rest of my .profile as above
fi

การ-nทดสอบควรกลับเป็นจริงเฉพาะในกรณีที่ความยาวของสตริงไม่เป็นศูนย์อย่างไรก็ตามแม้ว่าจะอยู่ในเซสชันด้านบนเมื่อฉันทำงานภายใต้/bin/sh -lมันจะส่งคืนสตริงว่างสำหรับ $ BASH_VERSION เมื่อรวมอยู่ใน. profile ของฉันเช่นนี้ มันผ่านการทดสอบ! พวกเขาดำเนินไปยังแหล่ง. bashrc ของฉันและให้ข้อผิดพลาดเหมือนเดิมกับฉัน

ตอนนี้ฉันสับสนจริงๆ


โปรดทราบว่าdash -lนอกจากนี้ยังแสดงให้เห็นว่ามีความคุ้มค่า$SHELL /bin/bash
Scott Severance

3
$SHELLเป็นสิ่งที่เขตข้อมูลสุดท้ายใน/etc/passwd(หรือgetent passwd) พูดว่า
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

@DennisWilliamson ขอบคุณนั่นคือสิ่งที่ฉันจำเป็นต้องรู้เพื่อค้นหาคำตอบที่ถูกต้อง
คา R Ledbetter

คุณทำผิด คุณควรใส่สภาพแวดล้อมที่ไม่เฉพาะเจาะจงในการ~/.profileทุบตีสิ่งที่เฉพาะเจาะจงในการทุบตี~/.bashrcและมี~/.bash_profileแหล่งที่มาทั้งสอง
nyuszika7h

คำตอบ:


12

คุณสามารถทำให้ความจริงที่$BASH_VERSIONว่างในการdashทำงานสำหรับคุณ:

if [ "$BASH_VERSION" = '' ]; then
    echo "This is dash."
else
    echo "This is bash."
fi

2
เทคนิค "x" เป็นสิ่งโบราณและจำเป็นสำหรับเปลือกหอยโบราณเท่านั้น ใช้if [ "$BASH_VERSION" = '' ]
หยุดชั่วคราวจนกว่าจะมีประกาศ

@DennisWilliamson: ขอบคุณ ฉันคิดว่าเทคนิคของคุณเฉพาะกับ Bash แต่ฉันแค่พักใน Dash และใช้งานได้ ฉันแก้ไขคำตอบของฉันแล้ว
Scott Severance

หรือเพียงแค่การใช้งาน-nหรืออะไร (+1, = ''ทำงานได้ดีอย่างสมบูรณ์)
Eliah Kagan

5

คุณต้องใช้เครื่องหมายคำพูดกับตัวแปรที่BASH_VERSIONจะใช้-n

if [ -n "$BASH_VERSION" ];then
 echo "this is bash"; 
else 
 echo "this is dash";
fi

1
ตั้งแต่ประเมินเท็จคุณไม่จำเป็นที่จะต้อง[ "$EMPTY_STRING" ] -nคุณเพียงแค่ต้องพูดตัวแปร
jeberle

2

ใช้/proc/[PID]/cmdlineเพื่อดูว่าสคริปต์ใดที่กำลังรันอยู่และทดสอบว่ามีอะไรอยู่บ้าง $$ตัวแปรจะให้เรา PID ของเปลือกเรียกใช้ ดังนั้นเราสามารถสร้างสคริปต์เช่นนี้

#!/bin/bash
if grep -q 'bash' /proc/$$/cmdline ;
then
    echo "This is bash"
else
    echo "This is some other shell"
fi

นี่คือการทดสอบของสคริปต์เดียวกัน:

$> bash test_script.sh                                                                                                
This is bash
$> dash test_script.sh                                                                                                
This is some other shell

สิ่งนี้จะไม่ทำงานบน Mac ตรวจสอบ $ BASH_VERSION
Austin Burk

2
@AustinBurk มันไม่จำเป็นต้องทำงานบน Mac นี่คือถามอูบุนตู
TheWanderer

@ Zacharee1 โอ้ยี้ฉันไม่ได้สนใจ:,)
Austin Burk

ฉันไม่ต้องการแก้ไขสิ่งนี้จากสิ่งที่คุณตั้งใจ แต่ฉันขอแนะนำให้พูดถึงข้อ จำกัด ของวิธีการนี้ ทุบตีไม่จำเป็นต้องมีbashชื่อ; ไม่ใช่เรื่องผิดปกติที่bashไฟล์ปฏิบัติการจะเรียกใช้ผ่าน symlink ด้วยชื่ออื่น โดยปกติแล้วใคร ๆ ก็ยังต้องการที่จะพิจารณาว่า Bash นอกจากนี้รูปแบบจะถูกจับคู่ทุกที่ใน/proc/$$/cmdlineซึ่งควรจะเป็นไปได้ที่จะแก้ไข แต่โปรดจำไว้ว่าข้อโต้แย้งในที่cmdlineคั่นด้วยตัวละครโมฆะ grep -qE '(^|/)bash$'รู้สึกเหมือนมันควรจะทำงาน bashแต่ให้เป็นบวกเท็จเมื่อโต้แย้งใด
Eliah Kagan

@EliahKagan คุณสามารถแก้ไขคำตอบของฉันได้ตลอดเวลา - คุณมีความเชี่ยวชาญเพียงพอดังนั้นฉันรู้ว่าการแก้ไขของคุณสามารถให้การปรับปรุงได้เท่านั้น คำตอบนั้นถูกเขียนขึ้นเมื่อฉันเป็นมิตรกับสิ่งแวดล้อมมากขึ้นกว่าตอนนี้
Sergiy Kolodyazhnyy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.