ทรัพยากรสำหรับการเขียนโปรแกรมเชลล์แบบพกพา


65

มีทรัพยากรใดบ้างสำหรับการเขียนโปรแกรมเชลล์แบบพกพา คำตอบที่ดีที่สุดคือการทดสอบบนแพลตฟอร์มเป้าหมายทั้งหมด แต่ก็ไม่ค่อยมีประโยชน์

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

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

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


2
NB โปรดอย่าตอบที่นี่เพียงเพื่ออ้างอิงเอกสารการปฏิบัติตามข้อกำหนดของการนำไปปฏิบัติโดยเฉพาะ หากคุณมีหนึ่งในนั้น wiki แท็กที่เกี่ยวข้องจะเป็นสถานที่ที่ดี
Gilles

1
มีคนต้องการขุดประวัติการแก้ไขสำหรับautoconfและMetaconfig(Perl, rn) และรวบรวมเทคนิคทั้งหมดและความคิดเห็นที่อธิบายได้ในที่เดียว
geekosaur

@geekosaur: คำแนะนำที่ดี ฉันไม่เคยดู internals ของ autoconf มีอะไรบ้างที่สามารถใช้เป็นแนวทางในการเขียนสคริปต์ของตัวเองได้หรือไม่? ถ้าเป็นเช่นนี้จะเป็นคำตอบที่ดีสำหรับคำถามของฉันแม้ว่าจะไม่ใช่คำตอบที่ชัดเจน
Gilles

5
ฉันแน่ใจว่าคุณทั้งคู่สามารถค้นหาได้อย่างง่ายดาย แต่เพื่อประโยชน์ของผู้อื่นที่ติดตามกระทู้นี้นี่คือลิงค์ไปยังหน้าเว็บที่เกี่ยวข้องจากคู่มือ autoconf: gnu.org/software/hello/manual/autoconf/Portable- Shell.html
J. Taylor

คำตอบ:


32

คู่มือ autoconf มีส่วนใน การเขียนโปรแกรมเปลือกแบบพกพา

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


3
นั่นเป็นหนึ่งในแหล่งข้อมูลที่ดีที่สุดและถูกสร้างขึ้นในขณะที่เขียนโค้ดใน M4 ที่ต้องผลิตเชลล์โค้ดที่พกพาข้ามเชลล์ได้มากที่สุด
Tim Post

6

นอกเหนือไปdashและposhมีbournesh(หรือbsh) ที่Heirloom บอร์นเชลล์ที่สามารถนำมาใช้ในการตรวจสอบBashisms

โครงการ Heirloom ยังรวมถึง "The Heirloom Toolchest" ซึ่งเป็นชุดของยูทิลิตี้ Unix มาตรฐานมากกว่า 100 รายการ (ซึ่งสามารถใช้เป็นจุดเริ่มต้นสำหรับการเปรียบเทียบตัวเลือกบรรทัดคำสั่ง)


2
โปรดทราบว่าเชลล์ Bourne ไม่ใช่ POSIX เชลล์การทำให้สคริปต์ของคุณสามารถพกพาไปยังเชลล์เป้าหมายได้นั้นหมายถึงการลดระดับไวยากรณ์ของสคริปต์ของคุณจากภาษา POSIX sh มาตรฐานไปเป็นตัวหารร่วมระหว่างนั้นและไวยากรณ์ของเชลล์เป้าหมาย ไม่คุ้มกับความคิดเห็นเว้นแต่คุณต้องการพกพาไปยังระบบโบราณ (หรือ Solaris 10 และก่อนหน้านี้และคุณไม่มีทางเลือกที่จะใช้ sh มาตรฐานซึ่งอยู่ใน / usr / xpg4 / bin ที่นั่น)
Stéphane Chazelas

5

คล้ายกับคำตอบนี้ลองรันสคริปต์ของคุณในหรู

นอกจากนี้อย่าลืมตั้งค่าPOSIXLY_CORRECTตัวแปรสภาพแวดล้อมเป็นจริงเนื่องจากจะทำให้โปรแกรมจำนวนมาก (ไม่เพียง แต่เชลล์) เพื่อให้เป็นไปตามมาตรฐาน POSIX อย่างเคร่งครัด


4

การเขียนสคริปต์ของคุณโดยใช้เส้นประอาจเป็นการเริ่มต้น


3
การทดสอบกับเส้นประเป็นขั้นต่ำเปลือยเพื่อหลีกเลี่ยงการพึ่งพาอุบัติเหตุเกี่ยวกับคุณสมบัติ ksh / ทุบตี แต่ฉันหลังจากกว่าว่ารู้เกี่ยวกับข้อบกพร่องในเปลือกหอย (เช่น zsh ของการจัดการกับดักยากจน) และเหนือสิ่งอื่นใดในสาธารณูปโภคเชลล์ (เช่น OpenBSD ของfindยังคง ไม่ได้ใช้งาน-exec +)
Gilles

FWIW OpenBSD findทำ-exec utility {} +ทุกวันนี้
Kusalananda

2

คุณสามารถลองใช้แพ็คเกจcheckbashismsของ Debian / Ubuntu devscriptsได้

มันไม่สมบูรณ์แบบ แต่มีประโยชน์ในการเป็นจุดเริ่มต้นที่มีอยู่ ตัวอย่างเช่นไม่เห็นข้อบกพร่องแบบคลาสสิกที่มีsed/ findเกี่ยวข้องกับ GNU vs BSD / ความแตกต่างอื่น ๆ

โดยค่าเริ่มต้นมันเป็นแบบเดเบียน + เส้น-pประการตั้งค่าสถานะอาจมีประโยชน์สำหรับในกรณีของคุณ


2

วันนี้คุณสามารถหาเชลล์ POSIX ได้จากระบบและโดยทั่วไปนั่นหมายความว่าคุณสามารถสคริปต์ในภาษา POSIX (โมดูโลทำงานในบั๊กการปฏิบัติตามกฎระเบียบ)

ปัญหาเดียว/bin/shคือในบางครั้งไม่ใช่ POSIX เชลล์ และคุณจะต้องเขียนโค้ด#!ลงในสคริปต์ที่ใช้งานได้ดี /path/to/posix/shell myscriptคุณก็ไม่สามารถขอให้ผู้ใช้ในการวิจัยปัญหาและเรียกใช้สคริปต์ของคุณเป็น

ดังนั้นเคล็ดลับคือการใช้คุณสมบัติ POSIX ในสคริปต์ของคุณ แต่ทำให้สคริปต์ค้นหาเชลล์ POSIX โดยอัตโนมัติ วิธีหนึ่งในการทำเช่นนี้:

#!/bin/sh

# At this point, we may be running under some old shell
# we have to tread carefully.

# note how we use test rather than [ ] syntax and avoid
# depending on test with no argument producing a failure;
# i.e. "test $posix_shell".

if ! test x$posix_shell = x ; then
  # the three possible shell paths are just an example;
  # please extend as necessary.

  for shell in /usr/xpg4/bin/sh /bin/bash /usr/bin/bash ; do
    if test -x $shell ; then
       posix_shell=$shell
    fi
  done
  if test x$posix_shell = x ; then
    echo "no POSIX shell found"
    exit 1
    # or we could avoid bailing here and just fall back on /bin/sh:
    # echo "falling back on /bin/sh: cross your fingers that it works"
    # posix_shell=/bin/sh
  fi
  export posix_shell

  # plain "$@" is broken in ancient shells! 
  # I seem to recall ${@+"$@"}: not sure if that's the right trick.

  exec $posix_shell $0 ${@+"$@"}  # can we count on exec in legacy shells? 
fi

# phew, at this point in the script we have been re-executed and are
# being interpreted by some reasonably modern shell. We can use $(...)
# command substitution, and other features.

มีวิธีการอื่นเช่นการสร้างรหัส เพิ่มสคริปต์ของคุณด้วยสคริปต์ขนาดเล็กที่ใช้เนื้อความของไฟล์สคริปต์โดยไม่มี #! บรรทัดและเพิ่มหนึ่งรายการ

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

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