ในความคิดเห็นต่อคำถามนี้มีกรณีเกิดขึ้นที่การใช้งาน sed หลาย ๆ ครั้งไม่เห็นด้วยกับโปรแกรมที่ค่อนข้างง่ายและเรา (หรืออย่างน้อยฉัน) ไม่สามารถระบุได้ว่าสเปคนั้นต้องการอะไร
ปัญหาคือพฤติกรรมของช่วงที่เริ่มต้นที่บรรทัดที่ถูกลบ:
1d;1,2d
ควรลบบรรทัด 2แม้ว่าจุดเริ่มต้นของช่วงจะถูกลบออกก่อนที่จะถึงคำสั่งนั้นหรือไม่ ความคาดหวังเริ่มต้นของฉันคือ "ไม่" สอดคล้องกับ BSD sed ในขณะที่ GNU sed พูดว่า "ใช่" และการตรวจสอบข้อความข้อกำหนดไม่ได้ช่วยแก้ปัญหาทั้งหมด
ที่ตรงกับความคาดหวังของฉัน (อย่างน้อย) MacOS และ Solaris sed
และ sed
BSD ไม่เห็นด้วยคือ (อย่างน้อย) GNU และ Busybox sed
และผู้คนมากมายที่นี่ สองคนแรกได้รับการรับรองจาก SUS ขณะที่คนอื่น ๆ มีแนวโน้มที่จะแพร่หลายมากขึ้น พฤติกรรมใดที่ถูกต้อง?
ข้อความข้อกำหนดสำหรับช่วงสองที่อยู่พูดว่า:
sedยูทิลิตี้แล้วให้ใช้บังคับในลำดับคำสั่งทั้งหมดที่มีอยู่เลือกพื้นที่รูปแบบที่จนกว่าคำสั่งเริ่มต้นรอบถัดไปหรือลาออก
และ
คำสั่งแก้ไขที่มีสองที่อยู่จะต้องเลือกช่วงที่ครอบคลุมจากพื้นที่รูปแบบแรกที่ตรงกับที่อยู่แรกผ่านพื้นที่รูปแบบต่อไปที่ตรงกับที่สอง [... ] เริ่มต้นที่บรรทัดแรกตามช่วงที่เลือก sed จะค้นหาที่อยู่แรกอีกครั้ง หลังจากนั้นกระบวนการจะทำซ้ำ
เนื้อหาที่บรรทัดที่ 2 อยู่ ใน "ช่วงรวมจากช่องว่างรูปแบบแรกที่ตรงกับที่อยู่แรกผ่านช่องว่างรูปแบบถัดไปที่ตรงกับที่สอง" โดยไม่คำนึงว่าจุดเริ่มต้นถูกลบไปแล้วหรือไม่ ในทางกลับกันฉันคาดว่าคนแรกที่d
จะไปสู่รอบต่อไปและไม่ให้โอกาสในการเริ่มต้น การใช้งานที่ได้รับการรับรอง UNIX ทำในสิ่งที่ฉันคาดหวัง แต่อาจไม่ใช่สิ่งที่ข้อกำหนดกำหนด
บางการทดลองทำตามตัวอย่าง แต่คำถามที่สำคัญคือสิ่งที่ควร sed
ทำเมื่อช่วงเริ่มต้นในบรรทัดลบ?
การทดลองและตัวอย่าง
การสาธิตปัญหาอย่างง่ายคือสิ่งนี้ซึ่งพิมพ์สำเนาของบรรทัดเพิ่มเติมแทนที่จะลบออก:
printf 'a\nb\n' | sed -e '1d;1,2p'
นี้จะให้sed
มีสองเส้นของการป้อนข้อมูลและa
b
โปรแกรมทำสองสิ่ง:
1d
ลบบรรทัดแรกกับd
คำสั่งจะลบพื้นที่รูปแบบและเริ่มรอบถัดไป และ
- เลือกช่วงของบรรทัดจาก 1 ถึง 2 และพิมพ์ออกมาอย่างชัดเจนนอกเหนือจากการพิมพ์อัตโนมัติทุกบรรทัดที่ได้รับ บรรทัดที่รวมอยู่ในช่วงจึงควรปรากฏสองครั้ง
ความคาดหวังของฉันคือสิ่งนี้ควรจะพิมพ์
b
เฉพาะกับช่วงที่ไม่ได้ใช้เพราะ1,2
ไม่เคยไปถึงในช่วงบรรทัดที่ 1 (เนื่องจากd
ข้ามไปยังรอบ / บรรทัดถัดไปแล้ว) ดังนั้นการรวมช่วงจึงไม่เริ่มขึ้นในขณะที่a
ถูกลบไปแล้ว Unix sed
s ที่สอดคล้องกันของ macOS และ Solaris 10 สร้างเอาต์พุตนี้เช่นเดียวกับที่ไม่ใช่ POSIX sed
ใน Solaris และ BSD sed
โดยทั่วไป
ในทางกลับกัน GNU ยังคงพิมพ์
b
b
แสดงว่ามีการตีความช่วง สิ่งนี้เกิดขึ้นทั้งในโหมด POSIX และไม่ใช่ sed ของ Busybox มีพฤติกรรมเหมือนกัน (แต่ไม่เหมือนกันเสมอไปดังนั้นมันดูเหมือนจะไม่เป็นผลมาจากรหัสที่ใช้ร่วมกัน)
ทดลองเพิ่มเติมกับ
printf 'a\nb\nc\nd\ne\n' | sed -e '2d;2,/c/p'
printf 'a\nb\nc\nd\ne\n' | sed -e '2d;2,/d/p'
พบว่าดูเหมือนว่าจะรักษาช่วงเริ่มต้นที่บรรทัดที่ถูกลบราวกับว่ามันเริ่มต้นในบรรทัดต่อไปนี้ มองเห็นได้เนื่องจาก/c/
ไม่ตรงกับช่วงสิ้นสุด ใช้/b/
ในการเริ่มต้นช่วงไม่ไม่2
ประพฤติตัวเช่นเดียวกับ
ตัวอย่างการทำงานครั้งแรกที่ฉันใช้คือ
printf '%s\n' a b c d e | sed -e '1{/a/d;};1,//d'
เป็นวิธีการลบทุกบรรทัดจนถึงการ/a/
แข่งขันนัดแรกแม้ว่าจะอยู่ในบรรทัดแรก (สิ่งที่ GNU จะใช้0,/a/d
สำหรับ - นี่เป็นการแสดงผลที่เข้ากันได้กับ POSIX)
มีคนแนะนำว่าสิ่งนี้ควรลบถึงการจับคู่ที่สองของ/a/
หากการจับคู่บรรทัดแรก (หรือทั้งไฟล์ถ้าไม่มีการจับคู่ที่สอง) ซึ่งดูเหมือนว่าน่าเชื่อถือ - แต่อีกครั้ง GNU เท่านั้นที่ทำเช่นนั้น ทั้ง macOS sed และ Solaris's sed สร้าง
b
c
d
e
สำหรับสิ่งนั้นตามที่ฉันคาดไว้ (GNU sed สร้างเอาต์พุตว่างจากการลบช่วงที่ไม่ได้ระบุไว้ Busybox sed พิมพ์เพียงd
และe
ซึ่งผิดอย่างชัดเจนไม่ว่าจะเกิดอะไรขึ้น) โดยทั่วไปฉันคิดว่าพวกเขาผ่านการทดสอบตามมาตรฐานการรับรองหมายความว่าพฤติกรรมของพวกเขาถูกต้อง แต่มีคนมากพอที่จะแนะนำอย่างอื่นว่าฉันไม่แน่ใจข้อความข้อกำหนดไม่น่าเชื่อถืออย่างสมบูรณ์และชุดทดสอบไม่สามารถ ครอบคลุมอย่างสมบูรณ์แบบ
เห็นได้ชัดว่ามันไม่สามารถพกพาได้จริง ๆ ที่จะเขียนโค้ดนั้นในวันนี้เนื่องจากความไม่สอดคล้องกัน แต่ในทางทฤษฎีแล้วมันควรจะเทียบเท่ากันทุกหนทุกแห่งด้วยความหมายหนึ่งหรืออื่น ๆ ฉันคิดว่านี่เป็นข้อผิดพลาด แต่ฉันไม่รู้ว่าการใช้งานแบบใดเพื่อรายงาน มุมมองของฉันในขณะนี้คือพฤติกรรมของ GNU และ Busybox sed ไม่สอดคล้องกับข้อกำหนด แต่ฉันเข้าใจผิดว่า
POSIX ต้องการอะไรที่นี่?
ed
โดยไม่ผ่านsed
ทั้งหมดหรือไม่