แสดงสองไฟล์เคียงข้างกัน


95

ไฟล์ข้อความที่ไม่เรียงลำดับ 2 ไฟล์ที่มีความยาวต่างกันจะแสดงเคียงข้างกันได้อย่างไร(ในคอลัมน์)ในไฟล์shell

ให้one.txtและtwo.txt:

$ cat one.txt
apple
pear
longer line than the last two
last line

$ cat two.txt
The quick brown fox..
foo
bar 
linux

skipped a line

แสดง:

apple                               The quick brown fox..
pear                                foo
longer line than the last two       bar 
last line                           linux

                                    skipped a line

paste one.txt two.txtเกือบจะใช้เคล็ดลับ แต่ไม่ได้จัดแนวคอลัมน์อย่างสวยงามเนื่องจากพิมพ์เพียงแท็บเดียวระหว่างคอลัมน์ 1 และ 2 ฉันรู้วิธีการนี้ด้วย emacs และ vim แต่ต้องการให้เอาต์พุตแสดงเป็น stdout สำหรับการวางท่อ ect

วิธีแก้ปัญหาที่ฉันใช้sdiffแล้วต่อท่อเพื่อ sed เพื่อลบเอาท์พุทsdiffเพิ่ม

sdiff one.txt two.txt | sed -r 's/[<>|]//;s/(\t){3}//'

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


ไม่ได้อยู่ในเปลือก แต่ควรค่าแก่การกล่าวขวัญ: ใช้meld !
fedorqui 'SO หยุดทำร้าย'

คำตอบ:


169

คุณสามารถใช้prเพื่อทำสิ่งนี้โดยใช้-mแฟล็กเพื่อรวมไฟล์หนึ่งไฟล์ต่อคอลัมน์และ-tเพื่อละเว้นส่วนหัวเช่น

pr -m -t one.txt two.txt

ผลลัพธ์:

apple                               The quick brown fox..
pear                                foo
longer line than the last two       bar
last line                           linux

                                    skipped a line

ดูสิ่งนี้ด้วย:


15
สมบูรณ์แบบ! รู้ว่ามีบางอย่างที่ไม่เคยได้ยินมาprก่อน ฉันลองใช้ 3 ไฟล์และผลลัพธ์ถูกตัดทอน แต่-wตัวเลือกแก้ไขได้ คำตอบที่ดี
Chris Seymour

5
@sudo_o: ยินดีที่ได้ช่วยเหลือ coreutils เต็มไปด้วยอัญมณี
Hasturkun

1
มีวิธีสำหรับ pr ในการตรวจจับความกว้างของหน้าจออัตโนมัติหรือไม่?
แมท

2
@Matt: คุณสามารถใช้$COLUMNSซึ่งควรมีให้โดยเชลล์
Hasturkun

1
เมื่อใช้พิมพ์สองไฟล์ข้างกันให้prตัดส่วนท้ายของเส้นยาว มีวิธีทำให้มันพันเส้นไหม
molnarg

32

หากต้องการขยายคำตอบของ@Hasturkun : โดยค่าเริ่มต้นprจะใช้เพียง 72 คอลัมน์สำหรับเอาต์พุต แต่ค่อนข้างง่ายที่จะทำให้ใช้คอลัมน์ที่มีอยู่ทั้งหมดในหน้าต่างเทอร์มินัลของคุณ:

pr -w $COLUMNS -m -t one.txt two.txt

เชลล์ส่วนใหญ่จะเก็บ(และอัปเดต) หน้าจอของเทอร์มินัลของคุณใน$COLUMNSตัวแปรสภาพแวดล้อมดังนั้นเราจึงส่งค่านั้นไปprเพื่อใช้สำหรับการตั้งค่าความกว้างของเอาต์พุต

สิ่งนี้ยังตอบคำถามของ@Matt :

มีวิธีสำหรับ pr ในการตรวจจับความกว้างของหน้าจอโดยอัตโนมัติหรือไม่?

ดังนั้นไม่: prตัวเองไม่สามารถตรวจจับความกว้างของหน้าจอได้ แต่เรากำลังช่วยเล็กน้อยโดยส่งผ่านความกว้างของเทอร์มินัลผ่าน-wตัวเลือก


7

หากคุณทราบว่าไฟล์อินพุตไม่มีแท็บให้ใช้คำตอบของ@oyss ที่expandง่ายขึ้น :

paste one.txt two.txt | expand --tabs=50

หากอาจมีแท็บในไฟล์อินพุตคุณสามารถขยายก่อนได้เสมอ:

paste <(expand one.txt) <(expand two.txt) | expand --tabs=50

6
paste one.txt two.txt | awk -F'\t' '{
    if (length($1)>max1) {max1=length($1)};
    col1[NR] = $1; col2[NR] = $2 }
    END {for (i = 1; i<=NR; i++) {printf ("%-*s     %s\n", max1, col1[i], col2[i])}
}'

การใช้*ข้อกำหนดรูปแบบช่วยให้คุณสามารถระบุความยาวฟิลด์แบบไดนามิก


1
ไม่เคยบอกว่าทำ แต่ถ้าฉันต้องการแสดงสองไฟล์เคียงข้างกันเป็นครั้งคราวการทำงานdiff -y one.txt two.txtจะทำได้ดีกว่าpaste one.txt two.txtการลบตัวอักษรพิเศษที่แตกต่างออกไปที่แสดงด้วยsedนั้นเป็นเรื่องเล็กน้อยเมื่อเทียบกับการเขียน / จดจำawkสคริปต์ แม้จะมีทั้งสองฟังก์ชันใน.bash_rcอีกต่อไป! = ดีขึ้นอ่านได้เร็วขึ้น .. ข้อดีตรงนี้คืออะไร?
Chris Seymour

2

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

paste one.txt two.txt |awk -F'\t' '{printf("%-50s %s\n",$1,$2)}'

2

หากคุณต้องการทราบความแตกต่างที่แท้จริงระหว่างสองไฟล์เคียงข้างกันให้ใช้diff -y:

diff -y file1.cf file2.cf

คุณยังสามารถตั้งค่าความกว้างเอาต์พุตโดยใช้-W, --width=NUMตัวเลือก:

diff -y -W 150 file1.cf file2.cf

และเพื่อให้diffเอาต์พุตคอลัมน์พอดีกับหน้าต่างเทอร์มินัลปัจจุบันของคุณ:

diff -y -W $COLUMNS file1.cf file2.cf

2

มีsedวิธี:

f1width=$(wc -L <one.txt)
f1blank="$(printf "%${f1width}s" "")"
paste one.txt two.txt |
    sed "
        s/^\(.*\)\t/\1$f1blank\t/;
        s/^\(.\{$f1width\}\) *\t/\1 /;
    "

ภายใต้ คุณสามารถใช้printf -v:

f1width=$(wc -L <one.txt)
printf -v f1blank "%${f1width}s"
paste one.txt two.txt |
    sed "s/^\(.*\)\t/\1$f1blank\t/;
         s/^\(.\{$f1width\}\) *\t/\1 /;"

(แน่นอนว่าวิธีแก้ปัญหาของ @Hasturkun prนั้นแม่นยำที่สุด !) :

ได้เปรียบsedกว่าpr

คุณสามารถเลือกความกว้างและหรือตัวคั่นได้อย่างละเอียด:

f1width=$(wc -L <one.txt)
(( f1width += 4 ))         # Adding 4 spaces
printf -v f1blank "%${f1width}s"
paste one.txt two.txt |
    sed "s/^\(.*\)\t/\1$f1blank\t/;
         s/^\(.\{$f1width\}\) *\t/\1 /;"

หรือสำหรับตัวอย่างเพื่อทำเครื่องหมายบรรทัดที่มีline:

f1width=$(wc -L <one.txt)
printf -v f1blank "%${f1width}s"
paste one.txt two.txt |
    sed "s/^\(.*\)\t/\1$f1blank\t/;
  /line/{s/^\(.\{$f1width\}\) *\t/\1 |ln| /;ba};
         s/^\(.\{$f1width\}\) *\t/\1 |  | /;:a"

จะแสดง:

apple                         |  | The quick brown fox..
pear                          |  | foo
longer line than the last two |ln| bar 
last line                     |ln| linux
                              |  | 
                              |ln| skipped a line

1

ค้นหาโซลูชันที่ใช้ python ด้านล่าง

import sys

# Specify the number of spaces between the columns
S = 4

# Read the first file
l0 = open( sys.argv[1] ).read().split('\n')

# Read the second file
l1 = open( sys.argv[2] ).read().split('\n')

# Find the length of the longest line of the first file
n = len(max(l0, key=len))

# Print the lines
for i in  xrange( max( len(l0), len(l1) ) ):

    try:
        print l0[i] + ' '*( n - len(l0[i]) + S) + l1[i]
    except:
        try:
            print ' ' + ' '*( n - 1 + S) + l1[i]
        except:
            print l0[i]

ตัวอย่าง

apple                            The quick brown fox..
pear                             foo
longer line than the last two    bar 
last line                        linux

                                 skipped a line

0
diff -y <file1> <file2>


[root /]# cat /one.txt
แอปเปิ้ล
ลูกแพร์
เส้นยาวกว่าสองเส้นสุดท้าย
บรรทัดสุดท้าย
[root /]# cat /two.txt
จิ้งจอกสีน้ำตาลด่วน ..
ฟู
บาร์
ลินุกซ์
[root@RHEL6-64 /]# diff -y one.txt two.txt
แอปเปิ้ล | จิ้งจอกสีน้ำตาลด่วน ..
ลูกแพร์ | ฟู
เส้นยาวกว่าสองเส้นสุดท้าย | บาร์
บรรทัดสุดท้าย | ลินุกซ์

sdiffเป็นdiff -yสิ่งที่ฉันพูดคุยในคำถาม
Chris Seymour

ใช่ถูกต้อง ... มีการกล่าวถึงเพื่อแสดงการตั้งค่าคำสั่ง / แฟล็กอื่นในการทำ
Vikas Jain

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