ฉันจะป้องกันไม่ให้ตัวเลือก 'shopt' ไม่สนับสนุนการทำให้เกิดข้อผิดพลาดใน. bashrc ของฉันได้อย่างไร


9

ฉันทำงานในสภาพแวดล้อมที่ค่อนข้างหลากหลายซึ่งฉันอาจใช้ Bash รุ่นต่างๆในโหนด HPC, VM หรือเวิร์กสเตชันส่วนตัวของฉัน เนื่องจากฉันใส่สคริปต์การเข้าสู่ระบบใน repo Git ฉันต้องการใช้ (ish) เดียวกัน.bashrcทั่วกระดานโดยไม่ต้อง "ถ้าโฮสต์นี้แล้ว ... " - ประเภทความยุ่งเหยิง

ผมชอบการทำงานเริ่มต้นของการทุบตี≤ 4.1 ที่ขยายcd $SOMEPATHเข้าไปในcd /the/actual/pathเมื่อกดTabคีย์ ในทุบตี 4.2 และสูงกว่าที่คุณจะต้องshopt -s direxpandเปิดใช้งานลักษณะการทำงานนี้และที่ไม่ได้เป็นใช้ได้จนกว่า 4.2.29 นี่เป็นเพียงตัวอย่างเดียว shoptตัวเลือกอื่นที่เกี่ยวข้องอาจเป็นไปได้complete_fullquote(แม้ว่าฉันไม่ทราบว่าสิ่งที่มันทำ) อาจมีการเปลี่ยนแปลงพฤติกรรมเริ่มต้นที่ v4.2

แต่direxpandไม่ได้รับการยอมรับจากรุ่นก่อนหน้าทุบตีและถ้าผมพยายามที่จะshopt -s direxpandอยู่ในของฉัน.bashrcที่ส่งผลให้เกิดข้อผิดพลาดถูกพิมพ์ไปยังคอนโซลครั้งที่ผมเข้าสู่โหนดกับเก่าทุบตีทุก:

-bash: shopt: direxpand: invalid shell option name

สิ่งที่ฉันต้องการจะทำคือล้อมรอบเงื่อนไขshop -s direxpandเพื่อเปิดใช้งานตัวเลือกนั้นใน Bash> 4.1 อย่างแข็งแกร่งโดยไม่ต้อง chashing เวอร์ชันเก่าของ Bash ( กล่าวคือไม่ใช่แค่เปลี่ยนเส้นทางเอาต์พุตข้อผิดพลาดไป/dev/null)


คำตอบของฉันไม่ช่วยได้อย่างไร
Luciano Andress Martini

@LucianoAndressMartini .bashrcมันได้และนั่นคือวิธีการแก้ปัญหาที่ผมจบลงไปด้วยในตัวฉันเอง ฉันยังต้องการบันทึกวิธีการใช้$BASH_VERSINFOเพื่อสอบถามเชลล์รุ่นหลัก / รุ่นรองสำหรับการแก้ไขของฉันเองซึ่งเป็นสาเหตุที่ฉันโพสต์คำตอบของฉันเอง :)
TheDudeAbides

ดูคำตอบของฉันฉันมีบางอย่างเกี่ยวกับการเปรียบเทียบรุ่นของโปรแกรมกับเชลล์สคริปต์
Luciano Andress Martini

คำตอบ:


14

ตรวจสอบว่าdirexpandมีอยู่ในผลลัพธ์ของshoptและเปิดใช้งานถ้ามันเป็น:

shopt | grep -q '^direxpand\b' && shopt -s direxpand

4
ดีกว่าให้ว่าgrep -q '^direxpand\b'ในกรณีที่บางรุ่นในอนาคตหรือการแยกของทุบตีมีตัวเลือกที่มีนี้เป็น substring และdirexpandลบ ไม่น่าเป็นไปได้ในกรณีเฉพาะนี้ แต่ก็ไม่ได้มีค่าใช้จ่ายมากนักที่จะแข็งแกร่ง
Gilles 'หยุดความชั่วร้าย'

ขอบคุณลูเซียโน ฉันตั้งใจจะตอบคำถามของฉันเอง แต่ฉันจะยอมรับคำตอบของคุณหลังจากการแก้ไขผ่านการตรวจสอบจากเพื่อนคุณอาจอนุมัติด้วยตนเองได้ไหม
TheDudeAbides

4
Bash อนุญาตให้สอบถามตัวเลือกเชลล์เฉพาะเพื่อให้สามารถ[ -z "$(shopt -po direxpand 2>&-)" ] || shopt -s direxpandใช้ได้ ไม่มีปัญหาของ regex! :-)
David Foerster

@DavidFoerster ฉันจะเปลี่ยนตรรกะไปรอบ ๆ : [ -n "blah" ] && shopt blahวิธีที่คุณพูดมันคุณกำลังพูดว่า "ถ้า direxpand ไม่ได้รับการสนับสนุนแล้วอย่าทำสิ่งนี้"
รวย

1
@ Rich: สคริปต์เชลล์ส่วนใหญ่ของฉันรวมset -eไว้ที่ด้านบนดังนั้นฉันมักจะใช้ตรรกะลัดแบบนี้
David Foerster

16

/dev/nullฉันไม่เห็นอะไรผิดปกติกับการเปลี่ยนเส้นทางข้อผิดพลาด หากคุณต้องการให้รหัสของคุณแข็งแกร่งให้set -eใช้สำนวนทั่วไป… || true:

shopt -s direxpand 2>/dev/null || true

หากคุณต้องการเรียกใช้รหัสสำรองหากไม่มีตัวเลือกให้ใช้สถานะการส่งคืนของshopt:

if shopt -s direxpand 2>/dev/null; then
   # the direxpand option exists
else
   # the direxpand option does not exist
fi

แต่ถ้าคุณไม่ชอบการเปลี่ยนเส้นทางข้อผิดพลาดออกไปจริงๆคุณสามารถใช้กลไกการทำให้สมบูรณ์เพื่อทำการวิปัสสนา นี่ถือว่าคุณไม่มีเครื่องจักรที่ล้าสมัยซึ่งมี bash ≤ 2.03 ที่ไม่สามารถตั้งโปรแกรมได้

shopt_exists () {
  compgen -A shopt -X \!"$1" "$1" >/dev/null
}
if shopt_exists direxpand; then
  shopt -s direxpand
fi

วิธีนี้หลีกเลี่ยงการฟอร์กซึ่งช้าในบางสภาพแวดล้อมเช่น Cygwin ตรงไปตรงมา2>/dev/nullฉันไม่คิดว่าคุณจะเอาชนะมันได้ในการแสดง


นั่นไม่ใช่ที่ที่สมองของฉันจะหายไป แต่ฉันชอบcompgenข้อเสนอ นั่นคือสิ่งที่ระดับตัวแทนที่นั่น! การหลีกเลี่ยงการเปลี่ยนเส้นทาง/dev/nullเป็นเพียงการตั้งค่าส่วนตัว ฉันต้องการขออนุญาตแทนที่จะให้อภัยถ้าเหมาะสมแล้ว :)
TheDudeAbides

+1 สำหรับการเรียนที่ไม่คาดคิดโดยสิ้นเชิงในโปรแกรมสำเร็จของ Bash ซึ่งบังคับให้ฉันไปที่คู่มือเพื่อถอดรหัสสิ่งที่compgen -A shopt -X ...ตั้งใจ
TheDudeAbides

4
@TheDudeAbides ฉันอ่านเกี่ยวกับการใช้compgenวิธีนี้บนUnix & Linuxฉันไม่รู้ว่าใครเสนอเป็นครั้งแรก (ฉันหยุดใช้ทุบตีเป็นเปลือกหลักของฉันก่อนที่จะเสร็จสิ้นการตั้งโปรแกรม) ในการเขียนโปรแกรมมันมักจะเป็นความคิดที่ดีที่จะขออนุญาตเพราะมีความเสี่ยงที่การตรวจสอบการอนุญาตจะไม่ตรงกับสิ่งที่คุณทำจริงเพราะการเข้ารหัส ข้อผิดพลาด (ในกรณีที่คุณไม่ได้ค่อนข้างตรวจสอบสิ่งที่คุณคิดว่าคุณกำลังตรวจสอบ) หรือเพราะสิ่งที่คุณตรวจสอบการเปลี่ยนแปลงก่อนที่คุณจะใช้มัน
Gilles 'หยุดชั่วร้าย'

5

เมื่อคุณทราบว่ามีshoptตัวเลือกเฉพาะในรุ่นใหญ่ / รุ่นรอง / แพตช์บางตัวของ Bash คุณสามารถตรวจสอบ$BASH_VERSIONตัวแปรหรือองค์ประกอบของ$BASH_VERSINFO[]อาร์เรย์เพื่อเปิดใช้งานตามเงื่อนไข

นี่คือการทดสอบสำหรับ Bash 4.2.29 ขึ้นไปรุ่นที่direxpand เปิดตัวครั้งแรกในซีรี่ส์ 4.2:

if [[ $BASH_VERSION == 4.2.* && ${BASH_VERSINFO[2]} -ge 29 ]] ||
   [[ ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -ge 3 ]] ||
   [[ ${BASH_VERSINFO[0]} -ge 5 ]]; then
    shopt -s direxpand
fi

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

หมายเหตุ: การจัดฟันที่อยู่รอบ ๆซึ่งจะต้องมีและการใช้และซึ่งทำจำนวนเต็มมากกว่า (ขึ้นอยู่กับสถานที่เกิดเหตุ) เปรียบเทียบคำศัพท์ หากไม่มีการอ้างอิง RHS ของโอเปอเรเตอร์จะถือเป็นรูปแบบ "extglob" ภายใน Bash / conditionals ดังที่กล่าวไว้ที่นี่ซึ่งทำให้สุนทรียศาสตร์มากกว่า${BASH_VERSINFO[index]}-eq-gt==[[]]

$BASH_VERSINFOอาร์เรย์ประกอบด้วยข้อมูลทั้งหมดที่คุณต้องการเห็นในการส่งออกของbash --version:

bash --version | head -1
# result:
# GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)

declare -p BASH_VERSINFO
# result:
# declare -ar BASH_VERSINFO='([0]="4" [1]="3" [2]="48" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")'

เมื่อไม่ชัดเจนจากเอกสารที่รองรับshoptเวอร์ชัน Bash หรือเปลี่ยนแปลงพฤติกรรมของพวกเขาวิธีการที่เสนอโดย Luciano นั้นใช้ได้:

# note the '-q' so that the matched pattern isn't actually printed
shopt | grep -q direxpand && shopt -s direxpand

... ตามที่เป็นวิธีแก้ปัญหาที่เสนอโดย Gilles เพียงละเว้นข้อผิดพลาด ( shopt -s direxpand 2>/dev/null) และอาจตรวจสอบ$?หากจำเป็นจริงๆ

ข้อมูลอ้างอิง: 1 , 2 , 3
การอ่านที่เกี่ยวข้อง: ตั้งค่าและ Shopt - Why Two?


นอกจากนี้คุณยังอาจจะสามารถใช้สิ่งที่ต้องการif [[ $BASH_VERSION > 4.3 ]];(ซึ่งตรงกับ4.3.0, 5.0ฯลฯ แต่ยัง4.3.0-alphaผมไม่ทราบว่าถ้าเรื่องจริงในภายหลัง..)
ilkkachu

สวัสดี @ilkkachu ขอบคุณสำหรับการแก้ไขเพื่อให้ครอบคลุม Bash v5.x direxpandตัวเลือกที่เป็นจริงที่สามารถใช้ได้สำหรับการทุบตี 4.2 แม้ว่า; ฉันได้ตรวจสอบแล้วด้วยภาพ Dockerที่ v4.2.53 โดยเรียกใช้docker run --rm bash:4.2 bash -c shopt | grep direxpand(และสำหรับการวัดที่ดีว่าไม่สามารถใช้งานได้จริงที่ v4.1.17 โดยใช้งานdocker run --rm bash:4.1 bash -c shopt | grep direxpand)
TheDudeAbides

อ่าฉันได้ทดสอบ4.2.0และสะดุดกับความจริงที่ว่ามันไม่ได้ทำงานที่นั่น การเปลี่ยนแปลงยังกล่าวถึงการเพิ่มเข้าbash-4.3-alphaด้วย ฉันก็คิดว่าจะต้องตรวจสอบ${BASH_VERSINFO[2]}ให้ถูกต้องเกี่ยวกับเรื่องนี้ แต่ฉันไม่ทราบว่าจุดที่เพิ่มเข้ามามัน ...
34825

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