ฉันถือว่าทุกคนที่นี่คุ้นเคยกับสุภาษิตว่าไฟล์ข้อความทั้งหมดควรลงท้ายด้วยบรรทัดใหม่ ฉันรู้จักกฎนี้มาหลายปีแล้ว แต่ฉันก็สงสัยอยู่เสมอว่าทำไม
ฉันถือว่าทุกคนที่นี่คุ้นเคยกับสุภาษิตว่าไฟล์ข้อความทั้งหมดควรลงท้ายด้วยบรรทัดใหม่ ฉันรู้จักกฎนี้มาหลายปีแล้ว แต่ฉันก็สงสัยอยู่เสมอว่าทำไม
คำตอบ:
เพราะนั่นเป็นวิธีที่มาตรฐาน POSIX กำหนดบรรทัด :
- 3.206 สาย
- ลำดับของอักขระที่ไม่ใช่ <newline> ที่เป็นศูนย์หรือมากกว่ารวมทั้งอักขระ <newline> ที่ยกเลิก
ดังนั้นบรรทัดที่ไม่ลงท้ายด้วยอักขระขึ้นบรรทัดใหม่จึงไม่ถือว่าเป็นบรรทัดที่แท้จริง นั่นเป็นสาเหตุที่บางโปรแกรมมีปัญหาในการประมวลผลบรรทัดสุดท้ายของไฟล์หากไม่ได้ขึ้นบรรทัดใหม่
มีข้อได้เปรียบอย่างน้อยหนึ่งข้อในแนวทางนี้เมื่อทำงานกับเทอร์มินัลอีมูเลเตอร์: เครื่องมือทั้งหมดของ Unix คาดว่าการประชุมนี้และทำงานกับมัน ตัวอย่างเช่นเมื่อเชื่อมไฟล์เข้าด้วยcat
กันไฟล์ที่ถูกยกเลิกโดยการขึ้นบรรทัดใหม่จะมีเอฟเฟกต์ที่แตกต่างจากที่ไม่มี:
$ more a.txt
foo
$ more b.txt
bar$ more c.txt
baz
$ cat {a,b,c}.txt
foo
barbaz
และตามตัวอย่างก่อนหน้านี้ยังแสดงให้เห็นเมื่อแสดงไฟล์บนบรรทัดคำสั่ง (เช่นผ่านmore
) ไฟล์ที่ถูกยกเลิกการขึ้นบรรทัดใหม่จะแสดงผลลัพธ์ที่ถูกต้อง ไฟล์ที่ถูกยกเลิกอย่างไม่ถูกต้องอาจถูกอ่านไม่ออก (บรรทัดที่สอง)
เพื่อความสอดคล้องจะเป็นประโยชน์อย่างมากในการทำตามกฎนี้ - มิฉะนั้นการทำเช่นนี้จะเกิดขึ้นเป็นพิเศษเมื่อต้องรับมือกับเครื่องมือ Unix ที่เป็นค่าเริ่มต้น
คิดให้แตกต่าง: ถ้าบรรทัดไม่ถูกยกเลิกด้วยการขึ้นบรรทัดใหม่การทำคำสั่งเช่นcat
มีประโยชน์นั้นยากกว่ามากคุณจะสร้างคำสั่งเพื่อเชื่อมไฟล์ต่าง ๆ ได้อย่างไร
b.txt
และc.txt
?แน่นอนว่าสิ่งนี้สามารถแก้ไขได้แต่คุณจำเป็นต้องใช้cat
ความซับซ้อนมากขึ้น (โดยการเพิ่มอาร์กิวเมนต์บรรทัดคำสั่งตำแหน่งเช่นcat a.txt --no-newline b.txt c.txt
) และตอนนี้คำสั่งมากกว่าแต่ละไฟล์แต่ละไฟล์จะควบคุมวิธีการวางร่วมกันกับไฟล์อื่น ๆ นี่เกือบจะไม่สะดวกอย่างแน่นอน
... หรือคุณต้องแนะนำตัวละครแมวมองพิเศษเพื่อทำเครื่องหมายบรรทัดที่ควรจะต่อเนื่องแทนที่จะถูกยกเลิก ทีนี้คุณก็ติดอยู่กับสถานการณ์เช่นเดียวกับ POSIX ยกเว้นการกลับด้าน (การต่อบรรทัดมากกว่าตัวอักขระการยกเลิกบรรทัด)
ตอนนี้ในระบบที่ไม่รองรับ POSIX (ทุกวันนี้ส่วนใหญ่เป็น Windows) ประเด็นคือ moot: โดยทั่วไปไฟล์จะไม่ลงท้ายด้วยการขึ้นบรรทัดใหม่และการนิยาม (ไม่เป็นทางการ) ของบรรทัดอาจเป็น "ข้อความที่คั่นด้วยการขึ้นบรรทัดใหม่" (สังเกตความสำคัญ) สิ่งนี้ถูกต้องทั้งหมด อย่างไรก็ตามสำหรับข้อมูลที่มีโครงสร้าง (เช่นโค้ดโปรแกรม) มันทำให้การแยกวิเคราะห์มีความซับซ้อนน้อยที่สุด: โดยทั่วไปหมายความว่าต้องมีการแยกวิเคราะห์ใหม่ ถ้า parser นั้นถูกเขียนด้วยนิยาม POSIX ในใจคุณอาจแก้ไขโทเค็นสตรีมได้ง่ายกว่าตัวแยกวิเคราะห์ - กล่าวอีกนัยหนึ่งให้เพิ่มโทเค็น "newline บรรทัดใหม่" ที่ส่วนท้ายของอินพุต
cat
ในทางที่มีประโยชน์และสอดคล้องกันมากขึ้น
แต่ละบรรทัดควรถูกยกเลิกด้วยอักขระขึ้นบรรทัดใหม่รวมถึงบรรทัดสุดท้าย บางโปรแกรมมีปัญหาในการประมวลผลบรรทัดสุดท้ายของไฟล์หากไม่ได้ขึ้นบรรทัดใหม่
GCC เตือนว่าไม่ใช่เพราะไม่สามารถประมวลผลไฟล์ได้ แต่เนื่องจากต้องเป็นส่วนหนึ่งของมาตรฐาน
มาตรฐานภาษา C บอกว่าไฟล์ต้นฉบับที่ไม่ว่างจะลงท้ายด้วยอักขระบรรทัดใหม่ซึ่งจะไม่นำหน้าด้วยอักขระแบ็กสแลชทันที
เนื่องจากนี่เป็นประโยค "จะ" เราจะต้องส่งข้อความวินิจฉัยสำหรับการละเมิดกฎนี้
นี่คือในส่วน 2.1.1.2 ของมาตรฐาน ANSI C 1989 ส่วน 5.1.1.2 ของมาตรฐาน ISO C 1999 (และอาจเป็นมาตรฐาน ISO C 1990 ด้วย)
อ้างอิง: จีซี / เก็บจดหมาย
wc -l
จะไม่นับบรรทัดสุดท้ายของไฟล์หากไม่ได้ขึ้นบรรทัดใหม่ นอกจากนี้cat
จะเข้าร่วมบรรทัดสุดท้ายของไฟล์โดยมีบรรทัดแรกของไฟล์ถัดไปเป็นไฟล์เดียวหากบรรทัดสุดท้ายของไฟล์แรกไม่ได้ขึ้นบรรทัดใหม่ โปรแกรมใด ๆ ที่กำลังมองหาบรรทัดใหม่มากในฐานะตัวคั่นมีศักยภาพที่จะทำให้เกิดปัญหาขึ้น
wc
ได้รับแล้วกล่าวถึง ....
cat
และwc
)
คำตอบนี้เป็นความพยายามในการตอบคำถามทางเทคนิคมากกว่าความเห็น
ถ้าเราต้องการที่จะเป็น POSIX purists เรากำหนดบรรทัดเป็น:
ลำดับของอักขระที่ไม่ใช่ <newline> ที่เป็นศูนย์หรือมากกว่ารวมทั้งอักขระ <newline> ที่ยกเลิก
ที่มา: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206
บรรทัดที่ไม่สมบูรณ์เป็น:
ลำดับของอักขระที่ไม่ใช่ <newline> ตั้งแต่หนึ่งตัวขึ้นไปที่ท้ายไฟล์
ที่มา: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195
ไฟล์ข้อความเป็น:
ไฟล์ที่มีตัวอักษรจัดเป็นศูนย์หรือมากกว่าบรรทัด บรรทัดไม่มีอักขระ NUL และไม่มีความยาวเกิน {LINE_MAX} ไบต์รวมถึงอักขระ <newline> แม้ว่า POSIX.1-2008 จะไม่แยกความแตกต่างระหว่างไฟล์ข้อความและไฟล์ไบนารี (ดูมาตรฐาน ISO C) แต่ยูทิลิตี้จำนวนมากจะสร้างเอาต์พุตที่สามารถคาดการณ์ได้หรือมีความหมายเมื่อทำงานกับไฟล์ข้อความ ยูทิลิตี้มาตรฐานที่มีข้อ จำกัด ดังกล่าวจะระบุ "ไฟล์ข้อความ" ในส่วน STDIN หรือ INPUT FILES เสมอ
ที่มา: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397
สตริงเป็น:
ลำดับที่ต่อเนื่องกันของไบต์ถูกยกเลิกโดยและรวมถึงไบต์แรกที่ว่าง
ที่มา: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396
จากนี้เราสามารถได้รับว่าครั้งเดียวที่เราอาจพบปัญหาประเภทใดคือถ้าเราจัดการกับแนวคิดของบรรทัดของไฟล์หรือไฟล์เป็นไฟล์ข้อความ (เป็นไฟล์ข้อความที่เป็นองค์กรของศูนย์ หรือมากกว่านั้นและบรรทัดที่เรารู้ว่าต้องจบด้วย <newline>)
กรณีในจุด: wc -l filename
.
จากwc
คู่มือของเราอ่าน:
บรรทัดถูกกำหนดเป็นสตริงของอักขระคั่นด้วยอักขระ <newline>
แล้วความหมายของไฟล์ JavaScript, HTML และ CSS คือ อะไรเป็นไฟล์ข้อความ ?
ในเบราว์เซอร์ IDEs ที่ทันสมัยและแอปพลิเคชันส่วนหน้าอื่น ๆ ไม่มีปัญหาในการข้าม EOL ที่ EOF แอปพลิเคชั่นจะวิเคราะห์ไฟล์อย่างถูกต้อง เนื่องจากไม่ใช่ว่าระบบปฏิบัติการทั้งหมดจะเป็นไปตามมาตรฐาน POSIX ดังนั้นจึงเป็นไปไม่ได้สำหรับเครื่องมือที่ไม่ใช่ระบบปฏิบัติการ (เช่นเบราว์เซอร์) เพื่อจัดการไฟล์ตามมาตรฐาน POSIX (หรือมาตรฐานระดับ OS ใด ๆ )
ด้วยเหตุนี้เราจึงค่อนข้างมั่นใจได้ว่า EOL ที่ EOF จะไม่มีผลกระทบเชิงลบต่อระดับแอปพลิเคชันโดยไม่คำนึงว่าจะทำงานบนระบบปฏิบัติการ UNIX หรือไม่
ณ จุดนี้เราสามารถพูดได้อย่างมั่นใจว่าการข้าม EOL ที่ EOF นั้นปลอดภัยเมื่อจัดการกับ JS, HTML, CSS ที่ฝั่งไคลเอ็นต์ ที่จริงแล้วเราสามารถระบุว่าการลดไฟล์ใดไฟล์หนึ่งโดยไม่มี <newline> นั้นปลอดภัย
เราสามารถก้าวไปอีกขั้นหนึ่งและบอกว่าเท่าที่ NodeJS เกี่ยวข้องมันก็ไม่สามารถปฏิบัติตามมาตรฐาน POSIX เพราะมันสามารถทำงานในสภาพแวดล้อมที่ไม่สอดคล้องกับ POSIX
เราจะเหลืออะไรอีกแล้ว เครื่องมือระดับระบบ
นี่หมายถึงปัญหาเฉพาะที่อาจเกิดขึ้นกับเครื่องมือที่ใช้ความพยายามในการปฏิบัติหน้าที่ตามความหมายของ POSIX (เช่นคำจำกัดความของบรรทัดดังแสดงในwc
)
แม้กระนั้นเชลล์บางตัวก็จะไม่ติด POSIX โดยอัตโนมัติ ยกตัวอย่างเช่นการทุบตีไม่ได้เริ่มต้นกับพฤติกรรม POSIX POSIXLY_CORRECT
มีสวิทช์ที่จะเปิดใช้งานได้คือ:
อาหารสำหรับความคิดเกี่ยวกับคุณค่าของ EOL ว่าเป็น <newline>: https://www.rfc-editor.org/old/EOLstory.txt
อยู่ในเส้นทางการขับรถสำหรับทุกความตั้งใจและจุดประสงค์ในการใช้งานลองพิจารณาสิ่งนี้:
มาทำงานกับไฟล์ที่ไม่มี EOL ในการเขียนไฟล์ในตัวอย่างนี้เป็น JavaScript แบบย่อที่ไม่มี EOL
curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o x.js
curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o y.js
$ cat x.js y.js > z.js
-rw-r--r-- 1 milanadamovsky 7905 Aug 14 23:17 x.js
-rw-r--r-- 1 milanadamovsky 7905 Aug 14 23:17 y.js
-rw-r--r-- 1 milanadamovsky 15810 Aug 14 23:18 z.js
สังเกตcat
ขนาดของไฟล์ว่าเป็นผลรวมของแต่ละส่วน หากการต่อไฟล์ JavaScript เป็นข้อกังวลสำหรับไฟล์ JS ข้อกังวลที่เหมาะสมกว่าคือการเริ่มต้นไฟล์ JavaScript แต่ละไฟล์ด้วยเซมิโคลอน
อย่างที่คนอื่นพูดถึงในเธรดนี้: ถ้าคุณต้องการcat
ไฟล์สองไฟล์ที่เอาต์พุตกลายเป็นหนึ่งบรรทัดแทนที่จะเป็นสองไฟล์ พูดอีกอย่างคือcat
ทำในสิ่งที่ควรทำ
man
ของcat
เพียงกล่าวถึงการอ่านการป้อนข้อมูลถึง EOF ไม่ <newline> โปรดทราบว่า-n
สวิตช์ของcat
จะพิมพ์บรรทัดที่ไม่ใช่ <newline> ที่สิ้นสุด (หรือบรรทัดที่ไม่สมบูรณ์ ) เป็นบรรทัดโดยที่จำนวนเริ่มต้นที่1 (ตามที่man
.)
-n กำหนดจำนวนบรรทัดเอาต์พุตโดยเริ่มต้นที่ 1
เมื่อเราเข้าใจวิธีที่ POSIX กำหนดบรรทัดแล้วพฤติกรรมนี้จะคลุมเครือหรือไม่เข้ากันได้
การทำความเข้าใจกับวัตถุประสงค์และการปฏิบัติตามเครื่องมือที่กำหนดจะช่วยในการกำหนดความสำคัญของการสิ้นสุดไฟล์ด้วย EOL ใน C, C ++, Java (JARs) ฯลฯ ... มาตรฐานบางอย่างจะกำหนดบรรทัดใหม่เพื่อความถูกต้อง - ไม่มีมาตรฐานดังกล่าวสำหรับ JS, HTML, CSS
ตัวอย่างเช่นแทนที่จะใช้wc -l filename
อย่างใดอย่างหนึ่งสามารถทำได้awk '{x++}END{ print x}' filename
และมั่นใจได้ว่าความสำเร็จของงานนั้นไม่ได้รับอันตรายจากไฟล์ที่เราอาจต้องการดำเนินการที่เราไม่ได้เขียน (เช่นห้องสมุดบุคคลที่สามเช่น minified JS เราcurl
d) - เว้นแต่เรา ความตั้งใจที่แท้จริงคือการนับบรรทัดในความหมายที่สอดคล้องกับ POSIX
ข้อสรุป
จะมีกรณีการใช้งานจริงน้อยมากที่การข้าม EOL ที่ EOF สำหรับไฟล์ข้อความบางอย่างเช่น JS, HTML และ CSS จะมีผลกระทบด้านลบ - ถ้าเป็นเช่นนั้น หากเราพึ่งพา <newline> แสดงตนเรากำลังจำกัดความน่าเชื่อถือของเครื่องมือของเราเฉพาะกับไฟล์ที่เราสร้างและเปิดตัวเราเองจนถึงข้อผิดพลาดที่อาจเกิดขึ้นจากไฟล์ของบุคคลที่สาม
คุณธรรมของเรื่องราว: เครื่องมือช่างที่ไม่มีจุดอ่อนในการพึ่งพา EOL ที่ EOF
รู้สึกฟรีเพื่อโพสต์กรณีการใช้งานเนื่องจากพวกเขาใช้กับ JS, HTML และ CSS ที่เราสามารถตรวจสอบว่าการข้าม EOL มีผลกระทบอย่างไร
มันอาจจะเกี่ยวข้องกับความแตกต่างระหว่าง :
หากแต่ละบรรทัดลงท้ายด้วย end-of-line สิ่งนี้จะหลีกเลี่ยงตัวอย่างเช่นการต่อไฟล์ข้อความสองไฟล์เข้าด้วยกันจะทำให้บรรทัดสุดท้ายของบรรทัดแรกวิ่งเข้าไปในบรรทัดแรกของบรรทัดที่สอง
นอกจากนี้ตัวแก้ไขยังสามารถตรวจสอบการโหลดได้ว่าไฟล์จะลงท้ายด้วย end-of-line หรือไม่และบันทึกไว้ในตัวเลือกท้องถิ่น 'eol' และใช้ไฟล์นั้นเมื่อทำการเขียนไฟล์
ไม่กี่ปีหลัง (2005) บรรณาธิการจำนวนมาก (ZDE, Eclipse, Scite, ... ) ได้ "ลืม" EOL สุดท้ายซึ่งไม่ได้ชื่นชมมากนัก
ไม่เพียงแค่นั้น แต่พวกเขาตีความ EOL สุดท้ายว่าไม่ถูกต้องในฐานะ 'เริ่มต้นบรรทัดใหม่' และเริ่มแสดงอีกบรรทัดหนึ่งราวกับว่ามันมีอยู่แล้ว
สิ่งนี้สามารถมองเห็นได้ด้วยไฟล์ข้อความ 'ที่ถูกต้อง' พร้อมโปรแกรมแก้ไขข้อความที่มีความประพฤติดีเช่น vim เปรียบเทียบกับการเปิดในโปรแกรมแก้ไขด้านบน มันแสดงบรรทัดพิเศษใต้บรรทัดสุดท้ายของไฟล์ คุณเห็นอะไรเช่นนี้:
1 first line
2 middle line
3 last line
4
เครื่องมือบางอย่างคาดหวังสิ่งนี้ ตัวอย่างเช่นwc
คาดหวังสิ่งนี้:
$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1
wc
ได้ว่าไม่ได้คาดหวังสิ่งนี้มากเท่าที่มันทำงานได้ง่ายภายในนิยาม POSIX ของ "บรรทัด" ซึ่งตรงข้ามกับความเข้าใจที่เข้าใจง่ายของ "บรรทัด" ของคนส่วนใหญ่
wc -l
การพิมพ์1
ในทั้งสองกรณี 2
แต่บางคนอาจจะบอกว่ากรณีที่สองควรพิมพ์
\n
เป็นตัวแบ่งบรรทัดแทนที่จะเป็นตัวคั่นบรรทัดดังที่ POSIX / UNIX ทำดังนั้นคาดว่ากรณีที่สองในการพิมพ์ 2 นั้นบ้าจริง ๆ
โดยทั่วไปมีหลายโปรแกรมที่จะไม่ประมวลผลไฟล์อย่างถูกต้องหากพวกเขาไม่ได้รับ EOL EOF ขั้นสุดท้าย
GCC เตือนคุณเกี่ยวกับสิ่งนี้เพราะคาดว่าเป็นส่วนหนึ่งของมาตรฐาน C (ส่วน 5.1.1.2 เห็นได้ชัด)
สิ่งนี้มาจากวันแรก ๆ เมื่อมีการใช้เทอร์มินัลอย่างง่าย อักขระขึ้นบรรทัดใหม่ถูกใช้เพื่อเรียก 'ล้างข้อมูลที่ถ่ายโอน
วันนี้อักขระขึ้นบรรทัดใหม่ไม่จำเป็นอีกต่อไป แน่นอนว่าแอพจำนวนมากยังคงมีปัญหาหากไม่มีการขึ้นบรรทัดใหม่ แต่ฉันคิดว่าจุดบกพร่องในแอพเหล่านั้น
หากคุณมีรูปแบบไฟล์ข้อความที่คุณต้องการให้ขึ้นบรรทัดใหม่คุณจะได้รับการตรวจสอบข้อมูลอย่างง่ายราคาถูกมาก: ถ้าไฟล์ลงท้ายด้วยบรรทัดที่ไม่มีบรรทัดใหม่ในตอนท้ายคุณจะรู้ว่าไฟล์เสีย มีเพียงหนึ่งไบต์พิเศษสำหรับแต่ละบรรทัดคุณสามารถตรวจพบไฟล์ที่เสียหายด้วยความแม่นยำสูงและแทบไม่มีเวลา CPU
กรณีการใช้งานแยกต่างหาก: เมื่อไฟล์ข้อความของคุณถูกควบคุมเวอร์ชัน (ในกรณีนี้โดยเฉพาะภายใต้คอมไพล์แม้ว่าจะใช้กับผู้อื่นด้วย) หากมีการเพิ่มเนื้อหาในตอนท้ายของไฟล์บรรทัดที่ก่อนหน้านี้บรรทัดสุดท้ายจะถูกแก้ไขเพื่อรวมอักขระบรรทัดใหม่ ซึ่งหมายความว่าการblame
inging ไฟล์เพื่อค้นหาว่าเมื่อใดที่บรรทัดที่ถูกแก้ไขล่าสุดจะแสดงการเพิ่มข้อความไม่ใช่การคอมมิชชันก่อนหน้านั้นที่คุณต้องการดู
\n
) แก้ไขปัญหา.
นอกเหนือจากเหตุผลในทางปฏิบัติข้างต้นแล้วมันจะไม่แปลกใจเลยถ้าผู้สร้าง Unix (Thompson, Ritchie, et al.) หรือผู้ทำ Multics รุ่นก่อนของพวกเขารู้ว่า คุณสามารถเข้ารหัสไฟล์ที่เป็นไปได้ทั้งหมด ด้วยตัวคั่นบรรทัดไม่มีความแตกต่างระหว่างไฟล์ของเส้นศูนย์และไฟล์ที่มีบรรทัดว่างหนึ่งบรรทัด ทั้งคู่ถูกเข้ารหัสเป็นไฟล์ที่มีอักขระศูนย์
ดังนั้นเหตุผลคือ:
wc -l
จะไม่นับ "บรรทัด" สุดท้ายหากไม่ได้ขึ้นบรรทัดใหม่cat
ทำงานได้ดีและทำงานได้โดยไม่มีความยุ่งยาก มันเพียงแค่คัดลอกไบต์ของแต่ละไฟล์โดยไม่จำเป็นต้องตีความใด ๆ ผมไม่คิดว่ามีเทียบเท่า DOS cat
เพื่อ การใช้copy a+b c
จะสิ้นสุดการผสานบรรทัดสุดท้ายของไฟล์ที่มีบรรทัดแรกของไฟล์a
b
ฉันสงสัยตัวเองมาหลายปีแล้ว แต่วันนี้ฉันเจอเหตุผลที่ดี
ลองนึกภาพไฟล์ที่มีการบันทึกในทุกบรรทัด (เช่นไฟล์ CSV) และคอมพิวเตอร์กำลังเขียนบันทึกที่ท้ายไฟล์ แต่มันก็ล้มเหลวทันที Gee เป็นบรรทัดสุดท้ายที่สมบูรณ์หรือไม่ (ไม่ใช่สถานการณ์ที่ดี)
แต่ถ้าเรายุติบรรทัดสุดท้ายเสมอเราก็จะรู้ (เพียงตรวจสอบว่าบรรทัดสุดท้ายถูกยกเลิก) มิฉะนั้นเราอาจจะต้องทิ้งบรรทัดสุดท้ายทุกครั้งเพื่อความปลอดภัย
สมมุติว่ารหัสการแยกวิเคราะห์บางอย่างคาดว่าจะมี
ฉันไม่แน่ใจว่าฉันจะพิจารณาว่าเป็น "กฎ" และแน่นอนว่าไม่ใช่สิ่งที่ฉันยึดมั่นในศาสนา รหัสที่เหมาะสมที่สุดจะรู้วิธีแยกวิเคราะห์ข้อความ (รวมถึงการเข้ารหัส) บรรทัดต่อบรรทัด (ตัวเลือกใด ๆ ของการสิ้นสุดบรรทัด) โดยมีหรือไม่ขึ้นบรรทัดใหม่ในบรรทัดสุดท้าย
แน่นอน - ถ้าคุณลงท้ายด้วยบรรทัดใหม่: มี (ในทางทฤษฎี) เป็นบรรทัดสุดท้ายที่ว่างเปล่าระหว่าง EOL และ EOF หรือไม่? หนึ่งในการไตร่ตรอง ...
นอกจากนี้ยังมีปัญหาการเขียนโปรแกรมในทางปฏิบัติด้วยไฟล์ที่ไม่มีบรรทัดใหม่ในตอนท้าย: read
Bash ในตัว (ฉันไม่รู้เกี่ยวกับread
การใช้งานอื่น ๆ) ไม่ทำงานตามที่คาดไว้:
printf $'foo\nbar' | while read line
do
echo $line
done
พิมพ์นี้เท่านั้นfoo
! เหตุผลก็คือเมื่อread
พบบรรทัดสุดท้ายมันจะเขียนเนื้อหาไป$line
แต่จะส่งกลับรหัสทางออก 1 เนื่องจากถึง EOF นี่เป็นการแบ่งwhile
ลูปดังนั้นเราจึงไม่เคยไปถึงecho $line
ส่วนนี้ หากคุณต้องการจัดการกับสถานการณ์นี้คุณต้องทำสิ่งต่อไปนี้:
while read line || [ -n "${line-}" ]
do
echo $line
done < <(printf $'foo\nbar')
กล่าวคือทำecho
ถ้าread
ล้มเหลวเนื่องจากบรรทัดไม่ว่างท้ายไฟล์ โดยธรรมชาติในกรณีนี้จะมีการขึ้นบรรทัดใหม่หนึ่งบรรทัดในเอาต์พุตที่ไม่ได้อยู่ในอินพุต
ทำไมไฟล์ (ข้อความ) ถึงลงท้ายด้วยการขึ้นบรรทัดใหม่
หลายคนแสดงออกเช่นกันเพราะ:
หลายโปรแกรมทำงานได้ไม่ดีหรือล้มเหลวหากไม่มี
แม้โปรแกรมที่จัดการกับไฟล์จะไม่มีจุดสิ้นสุด'\n'
ฟังก์ชั่นของเครื่องมืออาจไม่เป็นไปตามความคาดหวังของผู้ใช้ซึ่งอาจไม่ชัดเจนในมุมนี้
โปรแกรมไม่อนุญาตขั้นสุดท้าย'\n'
(ฉันไม่ทราบเลย)
แต่นี่เป็นคำถามต่อไป:
รหัสควรทำอย่างไรกับไฟล์ข้อความที่ไม่มีบรรทัดใหม่
ที่สำคัญที่สุด - ไม่ได้เขียนรหัสที่ถือว่าเป็นไฟล์ข้อความปลายมีขึ้นบรรทัดใหม่ การสันนิษฐานว่าไฟล์เป็นไปตามรูปแบบที่นำไปสู่ความเสียหายของข้อมูลการโจมตีของแฮ็กเกอร์และการล่ม ตัวอย่าง:
// Bad code
while (fgets(buf, sizeof buf, instream)) {
// What happens if there is no \n, buf[] is truncated leading to who knows what
buf[strlen(buf) - 1] = '\0'; // attempt to rid trailing \n
...
}
หากต้องการการติดตามครั้งสุดท้าย'\n'
แจ้งเตือนผู้ใช้ถึงการขาดงานและการดำเนินการ IOW ตรวจสอบความถูกต้องของรูปแบบของไฟล์ หมายเหตุ: สิ่งนี้อาจรวมถึงความยาวบรรทัดสูงสุดการเข้ารหัสอักขระ ฯลฯ
'\n'
กำหนดอย่างชัดเจนเอกสารการจัดการรหัสของที่หายไปสุดท้าย
ไม่ได้เป็นไปได้สร้าง'\n'
ไฟล์ขาดเป็นตอนจบ
มันช้ามากที่นี่ แต่ฉันเพิ่งพบข้อผิดพลาดหนึ่งในการประมวลผลไฟล์และที่มาเพราะไฟล์ไม่ได้ลงท้ายด้วยบรรทัดใหม่ที่ว่างเปล่า เรากำลังประมวลผลไฟล์ข้อความด้วยsed
และsed
ละเว้นบรรทัดสุดท้ายจากเอาต์พุตซึ่งทำให้โครงสร้าง json ไม่ถูกต้องและการส่งส่วนที่เหลือของกระบวนการล้มเหลว
สิ่งที่เราทำคือ:
มีไฟล์ตัวอย่างหนึ่งไฟล์ที่บอกว่า: foo.txt
มีjson
เนื้อหาอยู่ข้างใน
[{
someProp: value
},
{
someProp: value
}] <-- No newline here
ไฟล์ถูกสร้างขึ้นในเครื่องแม่ม่ายและสคริปต์หน้าต่างกำลังประมวลผลไฟล์นั้นโดยใช้คำสั่ง PowerShell ทั้งหมดดี.
เมื่อเราประมวลผลไฟล์เดียวกันโดยใช้sed
คำสั่งsed 's|value|newValue|g' foo.txt > foo.txt.tmp
ไฟล์ที่สร้างขึ้นใหม่คือ
[{
someProp: value
},
{
someProp: value
และบูมมันล้มเหลวในกระบวนการที่เหลือเพราะ JSON ไม่ถูกต้อง
ดังนั้นจึงเป็นการดีที่จะจบไฟล์ของคุณด้วยบรรทัดใหม่ที่ว่างเปล่า
ฉันอยู่ภายใต้การแสดงผลเสมอกฎมาจากวันที่แยกไฟล์โดยไม่ต้องขึ้นบรรทัดใหม่เป็นเรื่องยาก นั่นคือคุณจะสิ้นสุดการเขียนโค้ดที่กำหนดจุดสิ้นสุดของบรรทัดโดยอักขระ EOL หรือ EOF มันง่ายกว่าที่จะสมมติว่าบรรทัดลงท้ายด้วย EOL
อย่างไรก็ตามฉันเชื่อว่ากฎนั้นมาจากคอมไพเลอร์ C ที่ต้องการขึ้นบรรทัดใหม่ และดังที่ระบุไว้ในคำเตือน“ ไม่มีการขึ้นบรรทัดใหม่เมื่อสิ้นสุดไฟล์” คอมไพเลอร์ #include จะไม่เพิ่มบรรทัดใหม่
ลองนึกภาพว่าไฟล์นั้นกำลังถูกประมวลผลในขณะที่ไฟล์นั้นยังคงถูกสร้างขึ้นโดยกระบวนการอื่น
มันอาจจะเกี่ยวข้องกับเรื่องนั้นเหรอ? แฟล็กที่ระบุว่าไฟล์พร้อมที่จะประมวลผล
ฉันชอบเส้นใหม่ที่ส่วนท้ายของไฟล์รหัสต้นฉบับ
อาจมีต้นกำเนิดมาจาก Linux หรือระบบ UNIX ทั้งหมดสำหรับเรื่องนั้น ฉันจำได้ว่ามีข้อผิดพลาดในการรวบรวม (gcc หากฉันไม่ผิดพลาด) เพราะไฟล์ซอร์สโค้ดไม่ได้จบด้วยบรรทัดใหม่ที่ว่างเปล่า เหตุใดจึงทำให้วิธีนี้เป็นสิ่งที่น่าสงสัย
IMHO มันเป็นเรื่องของสไตล์และความคิดเห็นส่วนตัว
ในสมัยก่อนฉันไม่ได้ขึ้นบรรทัดใหม่ อักขระที่บันทึกหมายถึงความเร็วที่มากขึ้นผ่านโมเด็ม 14.4K นั้น
ต่อมาฉันวางบรรทัดใหม่เพื่อให้ง่ายขึ้นในการเลือกบรรทัดสุดท้ายโดยใช้ shift + downarrow