มีเหตุผลหลายประการที่การอ่านไฟล์ทั้งหมดในพื้นที่รูปแบบอาจผิดพลาดได้ ปัญหาตรรกะในคำถามโดยรอบบรรทัดสุดท้ายเป็นปัญหาทั่วไป มันเกี่ยวข้องกับsed
วงจรของสาย - เมื่อไม่มีอีกแล้วและsed
พบ EOF มันผ่าน - มันหยุดการประมวลผล ดังนั้นถ้าคุณอยู่ในบรรทัดสุดท้ายและคุณแนะนำsed
ให้รับมันก็จะหยุดอยู่ตรงนั้นและไม่ทำอะไรอีก
ที่กล่าวว่าหากคุณต้องการอ่านไฟล์ทั้งหมดลงในพื้นที่รูปแบบจริงๆแล้วมันก็น่าจะคุ้มค่าที่จะพิจารณาเครื่องมืออื่นอยู่ดี ความจริงก็คือsed
เป็นตัวแก้ไขกระแสที่มีความหมายเหมือนกัน - มันถูกออกแบบมาเพื่อทำงานเป็นสาย - หรือบล็อกข้อมูลแบบลอจิคัล - ในเวลาเดียวกัน
มีเครื่องมือที่คล้ายกันหลายอย่างที่ติดตั้งดีกว่าเพื่อจัดการบล็อกไฟล์แบบเต็ม ed
และex
ตัวอย่างเช่นสามารถทำสิ่งที่sed
สามารถทำได้และมีไวยากรณ์ที่คล้ายกัน - และอื่น ๆ นอกเหนือจาก - แต่แทนที่จะทำงานเฉพาะในอินพุตสตรีมในขณะที่เปลี่ยนเป็นเอาต์พุตเช่นเดียวกับsed
พวกเขายังรักษาไฟล์สำรองชั่วคราวในระบบไฟล์ . งานของพวกเขามีบัฟเฟอร์ไปยังดิสก์ตามความจำเป็นและพวกเขาจะไม่ลาออกอย่างกะทันหันในตอนท้ายของไฟล์(และมีแนวโน้มที่จะระเบิดมากน้อยมักจะภายใต้ความเครียดบัฟเฟอร์) ยิ่งไปกว่านั้นพวกเขายังมีฟังก์ชั่นที่มีประโยชน์มากมายซึ่งsed
ไม่เรียงลำดับที่ไม่สมเหตุสมผลในบริบทของสตรีมเช่นเครื่องหมายบรรทัดเลิกทำบัฟเฟอร์ที่ตั้งชื่อเข้าร่วมและอื่น ๆ
sed
จุดแข็งหลักของมันคือความสามารถในการประมวลผลข้อมูลทันทีที่อ่านได้อย่างรวดเร็วมีประสิทธิภาพและในสตรีม เมื่อคุณ slurp ไฟล์ที่คุณทิ้งและคุณมักจะพบปัญหากรณีขอบเช่นปัญหาบรรทัดสุดท้ายที่คุณพูดถึงและบัฟเฟอร์ overruns และประสิทธิภาพสุดขีด - ในขณะที่ข้อมูลจะแยกวิเคราะห์ยาวขึ้นเวลาประมวลผลของเครื่องมือ regexp เมื่อระบุการจับคู่ เพิ่มขึ้นชี้แจง
เกี่ยวกับจุดสุดท้ายนั้นโดยวิธี: ในขณะที่ฉันเข้าใจs/a/A/g
กรณีตัวอย่างน่าจะเป็นเพียงตัวอย่างไร้เดียงสาและอาจไม่ใช่สคริปต์จริงที่คุณต้องการรวบรวมในอินพุตคุณอาจพบว่ามันคุ้มค่าในการทำความคุ้นเคยกับy///
. หากคุณมักจะพบว่าตัวเองกำลังg
ทดแทนตัวละครตัวหนึ่งไปอีกตัวหนึ่งแบบ lobally นั่นy
อาจจะมีประโยชน์มากสำหรับคุณ มันคือการเปลี่ยนแปลงเมื่อเทียบกับการทดแทนและเร็วกว่าเพราะไม่ได้หมายความว่า regexp จุดหลังนี้สามารถทำให้มีประโยชน์เมื่อพยายามรักษาและทำซ้ำ//
ที่อยู่เปล่า ๆเพราะมันไม่ได้ส่งผลกระทบต่อพวกเขา แต่จะได้รับผลกระทบจากพวกเขา ไม่ว่าในกรณีใดy/a/A/
ก็เป็นวิธีที่ง่ายกว่าในการทำสิ่งเดียวกันให้สำเร็จและสามารถสลับได้เช่นกัน:y/aA/Aa/
ซึ่งจะแลกเปลี่ยนบน / ตัวพิมพ์เล็กทั้งหมดบนบรรทัดซึ่งกันและกัน
คุณควรทราบด้วยว่าพฤติกรรมที่คุณอธิบายไม่ใช่สิ่งที่ควรจะเกิดขึ้น
จาก GNU info sed
ในส่วนข้อบกพร่องที่รายงานโดยทั่วไป :
N
คำสั่งในบรรทัดสุดท้าย
sed
ทางออกส่วนใหญ่โดยไม่พิมพ์อะไรเมื่อN
ออกคำสั่งในบรรทัดสุดท้ายของไฟล์ GNU sed
พิมพ์พื้นที่รูปแบบก่อนออกจากนอกเสียจากว่า-n
ได้ระบุสวิตช์คำสั่งแล้ว ตัวเลือกนี้เกิดจากการออกแบบ
ตัวอย่างเช่นพฤติกรรมของsed N foo bar
จะขึ้นอยู่กับว่า foo มีจำนวนบรรทัดคู่หรือคี่ หรือเมื่อเขียนสคริปต์เพื่ออ่านไม่กี่บรรทัดต่อไปดังต่อไปนี้การแข่งขันรูปแบบการใช้งานแบบดั้งเดิมของการsed
จะบังคับให้คุณเขียนสิ่งที่ต้องการแทนเพียง/foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N }
/foo/{ N;N;N;N;N;N;N;N;N; }
ไม่ว่าในกรณีใดวิธีแก้ปัญหาที่ง่ายที่สุดคือใช้$d;N
ในสคริปต์ที่ต้องอาศัยลักษณะการทำงานดั้งเดิมหรือตั้งค่าPOSIXLY_CORRECT
ตัวแปรเป็นค่าที่ไม่ว่างเปล่า
POSIXLY_CORRECT
ตัวแปรสภาพแวดล้อมที่ถูกกล่าวถึงเพราะระบุ POSIX ว่าถ้าsed
การเผชิญหน้า EOF เมื่อที่พยายามN
มันควรจะลาออกโดยไม่ต้องออก แต่รุ่น GNU จงใจแบ่งมาตรฐานในกรณีนี้ โปรดทราบว่าแม้ในขณะที่พฤติกรรมนั้นเป็นธรรมเหนือข้อสันนิษฐานก็คือกรณีข้อผิดพลาดเป็นหนึ่งในการแก้ไขกระแส - ไม่ slurping ไฟล์ทั้งหมดในหน่วยความจำ
มาตรฐานกำหนดN
พฤติกรรมดังนี้:
N
ผนวกอินพุตบรรทัดถัดไปโดยลด\n
ewline ที่ถูกยกเลิกลงในพื้นที่รูปแบบโดยใช้\n
ewline ในตัวเพื่อแยกวัสดุที่ต่อท้ายออกจากวัสดุดั้งเดิม โปรดทราบว่าการเปลี่ยนแปลงหมายเลขบรรทัดปัจจุบัน
หากไม่มีบรรทัดอินพุตถัดไปN
คำสั่งกริยาจะแยกไปที่ส่วนท้ายของสคริปต์และออกโดยไม่เริ่มรอบใหม่หรือคัดลอกพื้นที่รูปแบบไปยังเอาต์พุตมาตรฐาน
เมื่อทราบว่ามีบาง GNU-ISMS อื่น ๆ ที่แสดงให้เห็นในคำถาม - โดยเฉพาะอย่างยิ่งการใช้งานของ:
ฉลากb
ไร่และวงเล็บฟังก์ชั่นบริบท{
}
เป็นกฎของหัวแม่มือsed
คำสั่งใด ๆที่ยอมรับพารามิเตอร์โดยพลการจะเข้าใจการกำหนดขอบเขตที่\n
ewline ในสคริปต์ ดังนั้นคำสั่ง ...
:arbitrary_label_name; ...
b to_arbitrary_label_name; ...
//{ do arbitrary list of commands } ...
... ทุกคนมีแนวโน้มที่จะปฏิบัติไม่ถูกต้องขึ้นอยู่กับการsed
ใช้งานที่อ่านได้ พวกเขาควรจะเขียน:
...;:arbitrary_label_name
...;b to_arbitrary_label_name
//{ do arbitrary list of commands
}
เดียวกันถือเป็นจริงสำหรับr
, w
, t
, a
, i
และ(และอาจจะขึ้นไม่กี่คนที่ฉันลืมในขณะนี้)c
ในเกือบทุกกรณีพวกเขาอาจจะเขียน:
sed -e :arbitrary_label_name -e b\ to_arbitary_label_name -e \
"//{ do arbitrary list of commands" -e \}
... โดยที่-e
คำสั่ง xecution ใหม่ย่อมาจาก\n
ewline delimiter ดังนั้นที่info
ข้อความGNU แนะนำการใช้งานแบบดั้งเดิมsed
จะบังคับให้คุณทำ :
/foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N }
... มันควรจะเป็น ...
/foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N
}
... แน่นอนว่าไม่เป็นความจริงเช่นกัน การเขียนบทในวิธีนั้นเป็นเรื่องที่ค่อนข้างงี่เง่า มีวิธีที่ง่ายกว่ามากในการทำเช่นเดียวกันเช่น:
printf %s\\n foo . . . . . . |
sed -ne 'H;/foo/h;x;//s/\n/&/3p;tnd
//!g;x;$!d;:nd' -e 'l;$a\' \
-e 'this is the last line'
... ที่พิมพ์:
foo
.
.
.
foo\n.\n.\n.$
.$
this is the last line
... เพราะt
คำสั่ง est - เหมือนกับsed
คำสั่งส่วนใหญ่- ขึ้นอยู่กับวงจรของวงจรเพื่อรีเฟรชรีจิสเตอร์รีเทิร์นและที่นี่วงจรของไลน์จะได้รับอนุญาตให้ทำงานส่วนใหญ่ได้ นั่นคือการแลกเปลี่ยนอีกอย่างที่คุณทำเมื่อคุณข้ามไฟล์ - รอบของบรรทัดจะไม่รีเฟรชอีกครั้งและการทดสอบจำนวนมากจะทำงานผิดปกติ
คำสั่งข้างต้นไม่เสี่ยงต่อการป้อนข้อมูลที่มากเกินไปเพราะมันจะทำการทดสอบง่ายๆเพื่อตรวจสอบสิ่งที่มันอ่านเมื่อมันอ่าน ด้วยH
บรรทัดเก่าทั้งหมดจะต่อท้ายพื้นที่พักสาย แต่ถ้าบรรทัดตรงกับ/foo/
นั้นจะแทนที่h
พื้นที่ว่างเก่า บัฟเฟอร์มีการx
เปลี่ยนแปลงe ถัดไปและs///
พยายามใช้การแทนที่แบบมีเงื่อนไขหากเนื้อหาของบัฟเฟอร์ตรงกับ//
รูปแบบสุดท้ายที่ระบุ ในคำอื่น ๆ//s/\n/&/3p
พยายามที่จะเข้ามาแทนที่การขึ้นบรรทัดใหม่ที่สามในพื้นที่ถือด้วยตัวเองและพิมพ์ผลถ้า/foo/
พื้นที่ถือในปัจจุบันตรงกับ หากการทำเช่นนี้t
ประสบความสำเร็จสคริปต์ก็จะแยกไปที่เลเบลn
ot d
elete ซึ่งทำหน้าที่เป็นl
ook และตัดคำสคริปต์ออก
ในกรณีที่ทั้งคู่/foo/
และบรรทัดที่สามไม่สามารถจับคู่ร่วมกันในพื้นที่พักแม้ว่า//!g
จะจะเขียนทับบัฟเฟอร์ถ้า/foo/
ไม่ตรงหรือถ้ามันถูกจับคู่ก็จะเขียนทับบัฟเฟอร์ถ้า\n
ewline ไม่ตรงกัน(ดังนั้นแทนที่/foo/
ด้วย ตัวเอง) การทดสอบที่ละเอียดเล็กน้อยนี้ช่วยป้องกันบัฟเฟอร์ไม่ให้เติมเต็มโดยไม่จำเป็นสำหรับการเหยียดยาวเป็นเวลานาน/foo/
และช่วยให้มั่นใจได้ว่ากระบวนการไม่ติดขัดเนื่องจากอินพุตไม่ซ้อนกัน ต่อไปนี้ในกรณีที่ไม่มี/foo/
หรือ//s/\n/&/3p
ล้มเหลวบัฟเฟอร์จะถูกสลับอีกครั้งและทุกบรรทัด แต่สุดท้ายจะถูกลบ
บรรทัดสุดท้าย$!d
- บรรทัดสุดท้าย- เป็นการสาธิตอย่างง่ายว่าsed
สคริปต์จากบนลงล่างสามารถจัดการหลายกรณีได้อย่างง่ายดาย เมื่อวิธีการทั่วไปของคุณคือการตัดกรณีที่ไม่ต้องการที่เริ่มต้นด้วยวิธีที่ทั่วไปที่สุดและทำงานไปยังกรณีที่เฉพาะเจาะจงที่สุดแล้วขอบสามารถจัดการได้ง่ายขึ้นเพราะพวกเขาได้รับอนุญาตให้ผ่านไปยังจุดสิ้นสุดของสคริปต์ด้วยข้อมูลอื่น ๆ ที่คุณต้องการ ทุกอย่างจะห่อคุณด้วยข้อมูลที่คุณต้องการเท่านั้น แม้ว่าการดึงเคสขอบดังกล่าวออกจากลูปปิดอาจทำได้ยากกว่า
และนี่คือสิ่งสุดท้ายที่ฉันต้องพูดว่า: หากคุณต้องดึงไฟล์ทั้งหมดออกมาจริงๆคุณสามารถยืนทำงานให้น้อยลงได้โดยอาศัยวงจรเส้นเพื่อทำเพื่อคุณ โดยทั่วไปแล้วคุณจะใช้N
ext และn
ext สำหรับlookahead - เพราะพวกมันก้าวหน้าไปก่อนวัฏจักรของเส้น แทนที่จะใช้ลูปปิดแบบวนซ้ำซ้อนในวง - เนื่องจากsed
วงรอบเป็นเพียงลูปการอ่านอย่างง่ายต่อไป - ถ้าจุดประสงค์ของคุณเพียงเพื่อรวบรวมอินพุตอย่างไม่เจาะจงก็อาจทำได้ง่ายกว่า:
sed 'H;1h;$!d;x;...'
... ซึ่งจะรวบรวมไฟล์ทั้งหมดหรือไปลอง
ข้อความด้านข้างเกี่ยวกับN
และพฤติกรรมบรรทัดสุดท้าย ...
ในขณะที่ฉันไม่มีเครื่องมือให้ฉันทดสอบให้พิจารณาว่าN
เมื่อการอ่านและการแก้ไขในสถานที่ทำงานแตกต่างกันหากไฟล์ที่แก้ไขเป็นไฟล์สคริปต์สำหรับการอ่านครั้งต่อไป