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


21

ฉันมีต้นไม้ใหญ่สองต้นซึ่งฉันต้องการเปรียบเทียบ ไฟล์บางไฟล์ในทรีแตกต่างกันเนื่องจากไฟล์หนึ่งมีการขึ้นบรรทัดใหม่ที่ส่วนท้ายและไฟล์อื่น ๆ จะขาดการขึ้นบรรทัดใหม่นี้ ฉันต้องการที่จะไม่สนใจความจริงข้อนี้ ฉันได้ลองโทรdiffแบบนี้แล้ว:

diff --ignore-all-space -r <dir1> <dir2>

และนี่คือการทำงาน ปัญหาของฉันคือมันไม่สนใจความแตกต่างอื่น ๆ (เกี่ยวข้องกับพื้นที่) ซึ่งอาจสำคัญ

โดยสรุป: ฉันแค่ต้องการละเว้นบรรทัดใหม่ที่ EOF เป็นไปได้ด้วยdiffหรือไม่

คำตอบ:


17

โดยทั่วไปคุณจำเป็นต้องเปรียบเทียบสองไฟล์โดยไม่สนใจไบต์ต่อท้าย ไม่มีตัวเลือก 'diff' ในการทำเช่นนี้ - แต่มีหลายวิธีที่สามารถทำได้ (เช่น hex diff ต่างก็คำนึงถึงเช่นกัน)

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

ตัวอย่างเช่นต่อไปนี้จะแก้ไขเนื้อหาของไฟล์ (ใช้sed -iเพื่อแก้ไขในสถานที่นี้เพียงพิมพ์ไปยัง stdout) เพื่อเพิ่มบรรทัดใหม่หากมีการขาดหายไป (หรือปล่อยให้ไฟล์ไม่เปลี่ยนแปลงหากมีการขึ้นบรรทัดใหม่แล้ว):

sed -e '$a\'  file1.txt

และเพื่อตรวจสอบไวยากรณ์ 'diff' (การคืนค่าจริงหมายถึงพวกมันเหมือนกันเท็จหมายถึงต่างกัน):

$ diff a/file1.txt   b/file1.txt  \
      && echo '** are same' || echo '** are different'
2c2
< eof
---
> eof
\ No newline at end of file
** are different

ตรวจสอบว่าช่องว่างเท่านั้นต่างกัน:

$ diff --ignore-all-space  a/file1.txt   b/file1.txt \
     && echo '** are same' || echo '** are different'
** are same

ในทุบตีเราสามารถใช้ 'sed' เพื่อจัดการเนื้อหาไฟล์ในขณะที่ส่งผ่านไปยัง 'diff' (ไฟล์ต้นฉบับไม่เปลี่ยนแปลง):

$ diff <(sed -e '$a\' a/file1.txt) <(sed -e '$a\' b/file1.txt) \
     && echo '** are same' || echo '** are different'
** are same

ตอนนี้สิ่งที่คุณต้องทำคือเลียนแบบdiff -rเพื่อเปรียบเทียบไดเรกทอรีซ้ำ หากเปรียบเทียบไดเรกทอรีaและbแล้วสำหรับไฟล์ทั้งหมดในa(เช่นa/dir1/dir2/file.txt) เส้นทางการสืบทอดมาเป็นแฟ้มในb(เช่นb/dir1/dir2/file.txt) และเปรียบเทียบ:

$ for f in $( find a -type f  )
> do
>    diff <(sed -e '$a\' $f) <(sed -e '$a\' b/${f#*/})
> done

รุ่น verbose เพิ่มเติมเล็กน้อย:

$ for f in $( find a -type f  )
> do
>   f1=$f
>   f2=b/${f#*/}
>   echo "compare: $f1 $f2"
>   diff <(sed -e '$a\' $f1) <(sed -e '$a\' $f2) \
>       && echo '** are same' || echo '** are different'
> done && echo '** all are same' || echo '** all are different'
compare: a/file1.txt b/file1.txt
** are same
compare: a/file2.txt b/file2.txt
** are same
** all are same

คุณช่วยอธิบายsed -e '$a\'ได้มั้ย ขอบคุณ
törzsmókus

เรียกใช้sedรับ-eสคริปต์ต่อไปนี้ ( ) / นิพจน์ซึ่งตรงกับจุดสิ้นสุดของไฟล์ ( $) และดำเนินการ "ผนวก" การกระทำ (a \) แต่ไม่ได้ระบุข้อความใด ๆ จริง ๆ (ไม่มีอะไรหลังจาก `\ ') ซึ่ง จะยังคงเพิ่ม EOF / บรรทัดใหม่ไปยังจุดสิ้นสุดของไฟล์ (เฉพาะในกรณีที่มันหายไป)
ไมเคิล

ขอบคุณ. ฉันไม่ได้เห็นa\ เลย
törzsmókus

1

ฉันแก้ไขปัญหาโดยการเพิ่มบรรทัดใหม่ให้กับแต่ละไฟล์และละเว้นบรรทัดว่างในส่วนต่าง (ตัวเลือก-B) โซลูชันนี้อาจไม่เหมาะกับกรณีการใช้งานของคุณ แต่อาจช่วยผู้อื่นได้:

echo >> $FILE1 
echo >> $FILE2
diff -B $FILE1 FILE2 

0

ไพพ์เอาต์พุตของdiffไปยังgrepคำสั่งที่ดร็อปข้อความที่คุณไม่ต้องการเห็น


ไม่ดี. diff -r มีอยู่พร้อมกับผล! = 0 ถ้าฉันไม่เพิ่ม --ignore-all-space เพื่อความชัดเจน: ฉันต้องการ diff ไม่สนใจบรรทัดใหม่ที่ EOF และเฉพาะที่ EOF และฉันต้องการให้รายงานผลลัพธ์ที่ตรงกับเกณฑ์นี้ นั่นคือถ้าไฟล์ในทรีแตกต่างกันเฉพาะขึ้นบรรทัดใหม่ที่ EOF นั้นจะต้องไม่ถูกพิจารณาว่าเป็นความแตกต่างดังนั้นจึงต้องส่งคืน 0
dangonfast

0

แค่คิดถึงวิธีการที่แตกต่างเช่นกันซึ่งจะทำงานกับไฟล์ที่มีขนาดใหญ่กว่า (และยังคงไม่คัดลอกหรือแก้ไขไฟล์ต้นฉบับ) คุณยังคงต้องจำลอง traversal ไดเรกทอรี recursive (และมีหลายวิธีที่จะทำเช่นนั้น) แต่ตัวอย่างนี้ไม่ได้ใช้ 'sed' แต่แทนที่จะเปรียบเทียบสองไฟล์โดยไม่รวมไบต์สุดท้ายที่ใช้cmpเช่น

$ cmp  a/file1.txt  b/file1.txt  && echo '** are same' || echo '** are different'
cmp: EOF on b/file1.txt
** are different

$ du -b a/file1.txt  b/file1.txt 
13  a/file1.txt
12  b/file1.txt

$ cmp  -n 12 a/file1.txt  b/file1.txt  && echo '** are same' || echo '** are different'
** are same

ยังคงวนซ้ำไฟล์ทั้งหมดในไดเรกทอรีและสำหรับสองไฟล์ a / file.txt และ b / file.txt ให้คำนวณขนาดไฟล์ที่ใหญ่กว่าและลบไฟล์หนึ่งจากนั้นทำ binary diff ( cmp) โดยใช้จำนวนไบต์นี้ (เช่นกันใน ทุบตี):

(( bytes = $(du -b a/file.txt  b/file.txt  | sort -nr | head -1  | cut -f1) - 1 ))
cmp -n $bytes a/file.txt b/file.txt

วนลูปไฟล์จะเป็นเช่นเดียวกับในคำตอบอื่น ๆ ที่ใช้และseddiff


0

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

diff -rqEeB fileA fileB 2> /dev/null

diff ส่งคืนค่า! = 0 ถ้าพบความแตกต่างและฉันต้องการตรวจสอบค่านั้น การเปลี่ยนเส้นทางไปยัง / dev / null ไม่ได้ทำให้ diff ลืมความแตกต่างนั้นดังนั้นค่าที่ส่งคืนคือ! = 0 ซึ่งฉันไม่ต้องการ ฉันต้องการ diff พิจารณาสองไฟล์เท่ากันหากความแตกต่างเพียงอย่างเดียวคือขึ้นบรรทัดใหม่ล่าสุด
dangonfast

-1

มีธงในต่าง commnad: --strip-trailing-crที่ทำสิ่งที่คุณขอ


-1 คุณเคยลองสิ่งนี้หรือไม่? มันปฏิบัติต่อ/r/nเหมือน/nและไม่มีอะไรเกี่ยวข้องกับการเสริม/nก่อน EOF
Kamil Maciorowski

ฉันได้ลองแล้วใช้มันเพื่อกระจายไฟล์ที่มีบรรทัดใหม่ dos / unix ต่างกัน ... มันไม่ถูกต้องเหรอ?
dharman

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