การเพิ่มบรรทัดใหม่ไปยังจุดสิ้นสุดของไฟล์คืออะไร


166

คอมไพเลอร์บางตัว (โดยเฉพาะ C หรือ C ++) ให้คำเตือนเกี่ยวกับ:

No new line at end of file

ฉันคิดว่านี่จะเป็นปัญหาเฉพาะโปรแกรมเมอร์ C แต่ github แสดงข้อความในมุมมองการส่ง:

\ No newline at end of file

สำหรับไฟล์ PHP

ฉันเข้าใจสิ่งที่ตัวประมวลผลล่วงหน้าได้อธิบายไว้ในหัวข้อนี้แต่สิ่งนี้เกี่ยวข้องกับ PHP หรือไม่ มันเป็นinclude()สิ่งเดียวกันหรือเกี่ยวข้อง\r\nกับ\nหัวข้อvs ?

จุดในการมีบรรทัดใหม่ที่ท้ายไฟล์คืออะไร



2
เพื่อฉี่คนออก
แอนดรู

3
หากคุณcatไฟล์พรอมต์ถัดไปจะถูกผนวกเข้ากับ "บรรทัดสุดท้าย" หากไม่ได้ขึ้นบรรทัดใหม่
Aaron Franke

คำตอบ:


185

มันไม่เกี่ยวกับการเพิ่มบรรทัดใหม่ที่ส่วนท้ายของไฟล์มันเกี่ยวกับการไม่ลบบรรทัดใหม่ที่ควรมี

แฟ้มข้อความภายใต้ยูนิกซ์ประกอบด้วยชุดของเส้นแต่ละที่ลงท้ายด้วยตัวอักษรขึ้นบรรทัดใหม่ ( \n) ไฟล์ที่ไม่ว่างเปล่าและไม่จบด้วยการขึ้นบรรทัดใหม่จึงไม่ใช่ไฟล์ข้อความ

ยูทิลิตี้ที่คาดว่าจะทำงานกับไฟล์ข้อความอาจไม่สามารถทำงานได้ดีกับไฟล์ที่ไม่ได้ขึ้นบรรทัดใหม่ ยูทิลิตี้ Unix เชิงประวัติอาจละเว้นข้อความหลังขึ้นบรรทัดใหม่ล่าสุดตัวอย่างเช่น โปรแกรมอรรถประโยชน์ของGNUมีนโยบายในการทำงานอย่างเหมาะสมกับไฟล์ที่ไม่ใช่ข้อความดังนั้นโปรแกรมอรรถประโยชน์ที่ทันสมัยอื่น ๆ ส่วนใหญ่จะทำเช่นนั้น แต่คุณยังอาจพบกับพฤติกรรมแปลก ๆ กับไฟล์ที่ไม่มีบรรทัดใหม่สุดท้าย

ด้วย GNU diff ถ้าไฟล์ใดไฟล์หนึ่งที่ถูกเปรียบเทียบจบลงด้วยการขึ้นบรรทัดใหม่ แต่ไม่ใช่ไฟล์อื่นมันควรระมัดระวังที่จะทราบข้อเท็จจริงนั้น เนื่องจาก diff เป็นแบบ line-oriented จึงไม่สามารถระบุสิ่งนี้ได้โดยการจัดเก็บ newline สำหรับไฟล์หนึ่งไฟล์ แต่ไม่ใช่สำหรับไฟล์อื่น - ขึ้นบรรทัดใหม่จำเป็นต้องระบุว่าแต่ละบรรทัดในไฟล์ diffเริ่มต้นและสิ้นสุดที่ใด ดังนั้น diff ใช้ข้อความพิเศษนี้\ No newline at end of fileเพื่อแยกความแตกต่างของไฟล์ที่ไม่ได้ลงท้ายด้วยการขึ้นบรรทัดใหม่จากไฟล์ที่ทำ

โดยวิธีการในบริบท C ไฟล์ต้นฉบับประกอบด้วยชุดของบรรทัด ยิ่งไปกว่านั้นหน่วยการแปลจะถูกดูในชุดการใช้งานซึ่งแต่ละชุดจะต้องลงท้ายด้วยอักขระขึ้นบรรทัดใหม่ ( n1256 §5.1.1.1) บนระบบ unix การแม็พนั้นง่าย บน DOS และ Windows แต่ละลำดับ CR LF ( \r\n) จะถูกแมปกับ newline ( \nนี่คือสิ่งที่เกิดขึ้นเสมอเมื่ออ่านไฟล์ที่เปิดเป็นข้อความบนระบบปฏิบัติการเหล่านี้) มี OSE สองสามตัวที่ไม่มีอักขระขึ้นบรรทัดใหม่ แต่มีเร็กคอร์ดขนาดคงที่หรือตัวแปรแทน บนระบบเหล่านี้การแมปจากไฟล์ไปยังแหล่ง C แนะนำ\nในตอนท้ายของแต่ละระเบียน แม้ว่าสิ่งนี้จะไม่เกี่ยวข้องโดยตรงกับยูนิกซ์ แต่ก็หมายความว่าหากคุณคัดลอกไฟล์ต้นฉบับ C ที่ไม่มีการขึ้นบรรทัดใหม่ขั้นสุดท้ายไปยังระบบที่มีไฟล์ข้อความแบบบันทึกจากนั้นก็คัดลอกกลับมาคุณจะจบลงด้วยความไม่สมบูรณ์ บรรทัดสุดท้ายจะถูกตัดทอนในการแปลงเริ่มต้นหรือขึ้นบรรทัดใหม่พิเศษที่ติดอยู่ระหว่างการแปลงย้อนกลับ

¹ ตัวอย่าง: ผลลัพธ์ของการจัดเรียง GNU จะจบลงด้วยการขึ้นบรรทัดใหม่เสมอ ดังนั้นถ้าไฟล์fooหายไปขึ้นบรรทัดสุดท้ายของคุณจะพบว่ารายงานตัวละครตัวหนึ่งมากกว่า sort foo | wc -ccat foo | wc -c


เกี่ยวกับ "... ชุดของบรรทัดแต่ละบรรทัดต้องลงท้ายด้วยอักขระขึ้นบรรทัดใหม่ (n1256 §5.1.1.1)" -> ในการดู C11dr N1570 ล่าสุดอีกครั้งไม่พบการสนับสนุนสำหรับสิ่งอื่นที่ไม่ใช่: "ไฟล์ต้นฉบับที่ไม่ว่างจะลงท้ายด้วยอักขระบรรทัดใหม่ซึ่งจะไม่ถูกนำหน้าด้วยอักขระแบ็กสแลชทันทีก่อนที่จะมีการประกบใด ๆ เกิดขึ้น" §5.1.1.2 2 แต่ดูเหมือนว่าจะถูก จำกัด ไว้เฉพาะข้อต่อแบบประกบ
chux

@chux ประโยคนั้นมีอยู่ใน n1256 ด้วย บรรทัดสุดท้ายต้องลงท้ายด้วยอักขระขึ้นบรรทัดใหม่ บรรทัดที่ไม่ใช่บรรทัดสุดท้ายต้องลงท้ายด้วยอักขระขึ้นบรรทัดใหม่อย่างชัดเจนเพื่อระบุว่าบรรทัดนั้นสิ้นสุดและบรรทัดถัดไปเริ่มต้นขึ้น ดังนั้นทุกบรรทัดต้องลงท้ายด้วยอักขระขึ้นบรรทัดใหม่
Gilles

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

> "ดังนั้นต่างใช้ข้อความพิเศษ \ ไม่มีการขึ้นบรรทัดใหม่ที่จุดสิ้นสุดของไฟล์เพื่อแยกความแตกต่างของไฟล์ที่ไม่ได้ลงท้ายด้วยการขึ้นบรรทัดใหม่จากไฟล์ที่ทำ" Git แสดงข้อความนี้ไม่เพียง แต่เมื่อเปรียบเทียบไฟล์เท่านั้น แต่แม้เมื่อไฟล์ใหม่ถูกเพิ่มเข้าไปในคอมไพล์ ดังนั้นอาร์กิวเมนต์นี้ไม่ถูกต้องฉันคิดว่า
Viktor Kruglikov

> "ยูทิลิตี้ที่ควรทำงานกับไฟล์ข้อความอาจไม่สามารถรับมือกับไฟล์ที่ไม่ได้ขึ้นบรรทัดใหม่ได้" ฉันไม่คิดว่ามันเป็นเรื่องของ git ที่ต้องใส่ใจกับปัญหาในระดับต่ำเช่นหายไป \ n เนื่องจาก POSIX ความต้องการ ฉันคิดว่าถ้า git แสดงข้อความนี้เหตุผลควรอยู่ในปัญหาการควบคุมแหล่งที่มา
Viktor Kruglikov

41

ไม่จำเป็นต้องมีเหตุผล แต่เป็นผลมาจากการปฏิบัติของไฟล์ที่ไม่ได้ลงท้ายด้วยบรรทัดใหม่:

catพิจารณาสิ่งที่จะเกิดขึ้นถ้าคุณต้องการที่จะประมวลผลไฟล์หลายใช้ ตัวอย่างเช่นหากคุณต้องการค้นหาคำfooที่จุดเริ่มต้นของบรรทัดใน 3 ไฟล์:

cat file1 file2 file3 | grep -e '^foo'

หากบรรทัดแรกใน file3 เริ่มต้นด้วยfooแต่ file2 ไม่มี\nบรรทัดสุดท้ายหลังจากบรรทัดสุดท้าย grep จะไม่พบเหตุการณ์นี้เนื่องจากบรรทัดสุดท้ายใน file2 และบรรทัดแรกใน file3 จะเห็นได้ว่า grep เป็นบรรทัดเดียว เส้น

ดังนั้นเพื่อความมั่นคงและเพื่อหลีกเลี่ยงความประหลาดใจฉันพยายามเก็บไฟล์ของฉันให้ลงท้ายด้วยบรรทัดใหม่เสมอ


แต่มันเป็นเรื่องของ git ที่ต้องใส่ใจกับการต่อไฟล์เข้าด้วยกัน?
Viktor Kruglikov

ไม่น่าจะเป็นเหตุผลที่คุณควรใส่'\n'แมวไว้ในการทำงานของแมว ...
แอนดรูว์

3
นั่นเป็นเหมือนการพูดว่า "บางครั้งฉันจะผนวก Strings ด้วยกันที่มี\nหรือ whitespace ในตอนท้ายดังนั้นเพื่อให้สิ่งต่าง ๆ สอดคล้องกันฉันมักจะใส่\n _____ปลายทั้งสองของสตริงเสมอ" ทีนี้สิ่งที่ถูกต้องที่ต้องทำก็คือให้ตัดสายของคุณแล้วต่อให้ถูกต้อง
แอนดรู

16

มีสองด้าน:

  1. มีคอมไพเลอร์ C บางตัวที่ไม่สามารถแยกบรรทัดสุดท้ายได้หากมันไม่ได้จบด้วยการขึ้นบรรทัดใหม่ มาตรฐาน C ระบุว่าไฟล์ C ควรลงท้ายด้วย newline (C11, 5.1.1.2, 2) และบรรทัดสุดท้ายที่ไม่มีบรรทัดใหม่ให้ผลการทำงานที่ไม่ได้กำหนด (C11, J.2, รายการที่ 2) อาจเป็นเพราะเหตุผลทางประวัติศาสตร์เนื่องจากผู้ขายคอมไพเลอร์บางรายเป็นส่วนหนึ่งของคณะกรรมการเมื่อมีการเขียนมาตรฐานแรก ดังนั้นคำเตือนโดย GCC

  2. diffโปรแกรม (เช่นใช้โดยgit diffgithub ฯลฯ ) แสดงความแตกต่างของบรรทัดระหว่างไฟล์ พวกเขามักจะพิมพ์ข้อความเมื่อไฟล์เดียวจบลงด้วยการขึ้นบรรทัดใหม่เพราะอื่นคุณจะไม่เห็นความแตกต่างนี้ ตัวอย่างเช่นหากความแตกต่างเพียงอย่างเดียวระหว่างสองไฟล์คือการปรากฏตัวของอักขระบรรทัดใหม่ล่าสุดโดยไม่มีคำใบ้มันจะดูเหมือนว่าทั้งสองไฟล์เหมือนกันเมื่อdiffและcmpส่งคืนรหัสออกสำเร็จไม่เท่ากันและ checksums ของไฟล์ (เช่นผ่านmd5sum) ไม่ตรงกัน


เข้ากับโปรแกรม diff
Thamaraiselvam

เสียงที่ต่างกันน่าจะฉลาดกว่า
Andrew

@ แอนดรูว์ไม่ก็ไม่ได้ diffคาดว่าจะพิมพ์ความแตกต่างหากมี และหากไฟล์หนึ่งมีอักขระขึ้นบรรทัดใหม่เป็นอักขระตัวสุดท้ายในขณะที่อีกไฟล์หนึ่งไม่มีความแตกต่างนั้นจะต้องสังเกตได้อย่างชัดเจนในผลลัพธ์
maxschlepzig

ข้อความสั่งหลังของคุณถูกต้อง อย่างไรก็ตามผู้ดู diff ไม่จำเป็นต้องแสดง "การขึ้นบรรทัดใหม่" ( \n) เพื่อเริ่มต้นด้วยมันสามารถเพียงแค่แสดง "บรรทัดใหม่" แทน
แอนดรู

10

\ No newline at end of fileคุณได้รับจากGitHubปรากฏในตอนท้ายของแพทช์ (ในdiffรูปแบบดูโน้ตที่ส่วนท้ายของ "แบบครบวงจรรูปแบบ" ส่วน)

คอมไพเลอร์ไม่สนใจว่าจะมีการขึ้นบรรทัดใหม่หรือไม่ในตอนท้ายของไฟล์ แต่git(และdiff/ / patchยูทิลิตี้) ต้องคำนึงถึงสิ่งเหล่านั้นในบัญชี มีสาเหตุหลายประการ ตัวอย่างเช่นการลืมเพิ่มหรือลบบรรทัดใหม่ที่ท้ายไฟล์จะเปลี่ยน hashsum ( md5sum/ sha1sum) นอกจากนี้ไฟล์อาจไม่ใช่โปรแกรมเสมอไปและสุดท้าย\nอาจสร้างความแตกต่าง

หมายเหตุ : เกี่ยวกับคำเตือนจากคอมไพเลอร์ C ฉันเดาว่าพวกเขายืนยันบรรทัดใหม่ขั้นสุดท้ายสำหรับวัตถุประสงค์ด้านความเข้ากันได้แบบย้อนหลัง คอมไพเลอร์เก่ามากอาจไม่ยอมรับบรรทัดสุดท้ายหากไม่ได้ลงท้ายด้วย\n(หรือลำดับถ่านที่ขึ้นอยู่กับระบบอื่น ๆ )


7
"ผมคิดว่าพวกเขายืนยันการขึ้นบรรทัดใหม่สุดท้ายสำหรับวัตถุประสงค์ในการเข้ากันได้" - Nope พวกเขายืนยันกับมันเพราะมาตรฐาน C เอกสารมัน
MestreLion

1
@MestreLion C ต้องขึ้นบรรทัดใหม่สุดท้ายสำหรับซอร์สโค้ด C (C11 §5.1.1.2 2) โปรดทราบว่าสำหรับไฟล์ข้อความ I / O, C มี "ไม่ว่าบรรทัดสุดท้ายจะต้องมีการยกเลิกอักขระบรรทัดใหม่หรือไม่คือการใช้งานที่กำหนด" §7.21.2 2
Chux

ใครใช้คอมไพเลอร์ตัวเก่ามาก ๆ หยุดใช้พวกเขา
Andrew

1
@MestreLion: และทำไมคุณถึงคิดว่ามาตรฐาน C สั่งให้มัน ...
Stéphane Gimenez

@ StéphaneGimenez: ความสอดคล้องความเข้ากันได้ที่ดีขึ้นและความสามารถในการทำงานร่วมกันระหว่างระบบปฏิบัติการที่แตกต่างกัน (POSIX ยังกำหนดบรรทัดที่ลงท้ายด้วย '\ n')
MestreLion

4

POSIX นี่คือชุดของมาตรฐานที่ระบุโดย IEEE เพื่อรักษาความเข้ากันได้ระหว่างระบบปฏิบัติการ

หนึ่งในนั้นคือคำจำกัดความของ "บรรทัด" ซึ่งเป็นลำดับที่ไม่ใช่ศูนย์หรือมากกว่าอักขระรวมถึงอักขระขึ้นบรรทัดใหม่ที่ยกเลิก

ดังนั้นสำหรับบรรทัดสุดท้ายนั้นที่จะรับรู้ว่าเป็น "บรรทัด" จริงมันควรจะมีการยกเลิกตัวอักษรขึ้นบรรทัดใหม่

นี่เป็นสิ่งสำคัญหากคุณขึ้นอยู่กับเครื่องมือของระบบปฏิบัติการที่จะบอกจำนวนบรรทัดหรือแยก / ช่วยแจงไฟล์ของคุณ ให้ PHP เป็นภาษาสคริปต์มันเป็นไปได้ทั้งหมดโดยเฉพาะอย่างยิ่งในวันแรกของมันหรือแม้กระทั่งตอนนี้ (ฉันไม่มีความคิด / postulating) มันมีการพึ่งพาระบบปฏิบัติการเช่นนั้น

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


3

นอกจากนี้ยังมีจุดในการรักษาประวัติศาสตร์ที่แตกต่าง หากไฟล์สิ้นสุดโดยไม่มีอักขระบรรทัดใหม่การเพิ่มสิ่งใด ๆ ไปยังจุดสิ้นสุดของไฟล์จะถูกดูโดยยูทิลิตี diff ในการเปลี่ยนบรรทัดสุดท้ายนั้น (เพราะ\nกำลังถูกเพิ่มเข้าไป)

ซึ่งอาจก่อให้เกิดผลที่ไม่พึงประสงค์ที่มีคำสั่งเช่นและgit blamehg annotate


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