Hiển thị hai tệp cạnh nhau


94

Làm cách nào để 2 tệp văn bản chưa được sắp xếp có độ dài khác nhau có thể được hiển thị cạnh nhau (theo cột) trong mộtshell

Cho one.txttwo.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

Trưng bày:

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

                                    skipped a line

paste one.txt two.txthầu như thực hiện thủ thuật nhưng không căn chỉnh các cột một cách đẹp mắt vì nó chỉ in một tab giữa cột 1 và cột 2. Tôi biết cách làm điều này với emacs và vim nhưng muốn đầu ra hiển thị thành stdout cho đường ống vv.

Giải pháp mà tôi đưa ra là sử dụng sdiffvà sau đó là các đường ống để loại bỏ đầu ra sdiffthêm vào.

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

Tôi có thể tạo một hàm và gắn nó vào .bashrcnhưng chắc chắn một lệnh cho điều này đã tồn tại (hoặc có khả năng là một giải pháp sạch hơn )?


Không phải trong một shell, nhưng điều đáng nói: sử dụng meld !
fedorqui 'VẬY đừng làm hại nữa'

Câu trả lời:


166

Bạn có thể sử dụng prđể làm điều này, sử dụng -mcờ để hợp nhất các tệp, một tệp trên mỗi cột và -tbỏ qua các tiêu đề, ví dụ:

pr -m -t one.txt two.txt

kết quả đầu ra:

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

                                    skipped a line

Xem thêm:


15
Hoàn hảo! Biết một cái gì đó sẽ tồn tại, chưa bao giờ nghe nói về prtrước đây. Tôi đã thử với 3 tệp và đầu ra đã bị cắt bớt nhưng -wtùy chọn đã giải quyết được điều đó. Câu trả lời rất hay.
Chris Seymour

5
@sudo_o: Rất vui khi được giúp đỡ, coreutils chứa đầy đá quý
Hasturkun

1
Có cách nào để pr tự động phát hiện chiều rộng màn hình không?
Matt

2
@Matt: Bạn có thể sử dụng $COLUMNS, cái này sẽ được cung cấp bởi shell.
Hasturkun

1
Khi được sử dụng để in hai tệp cạnh nhau, hãy prcắt phần cuối của các dòng dài. Có cách nào để làm cho nó quấn các dòng không?
molnarg

32

Để mở rộng một chút về câu trả lời của @Hasturkun : theo mặc định prchỉ sử dụng 72 cột cho đầu ra của nó, nhưng tương đối dễ dàng để làm cho nó sử dụng tất cả các cột có sẵn trong cửa sổ đầu cuối của bạn:

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

Hầu hết các shell sẽ lưu trữ (và cập nhật) chiều rộng màn hình của thiết bị đầu cuối của bạn trong $COLUMNSbiến môi trường, vì vậy chúng tôi chỉ chuyển giá trị đó sang prđể sử dụng cho cài đặt chiều rộng đầu ra của nó.

Điều này cũng trả lời câu hỏi của @Matt :

Có cách nào để pr tự động phát hiện chiều rộng màn hình không?

Vì vậy, không: prbản thân nó không thể phát hiện ra chiều rộng màn hình, nhưng chúng tôi đang giúp một chút bằng cách chuyển chiều rộng của thiết bị đầu cuối thông qua -wtùy chọn.


7

Nếu bạn biết các tệp đầu vào không có tab, thì việc sử dụng sẽ expandđơn giản hóa câu trả lời của @oyss :

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

Nếu có thể có các tab trong tệp đầu vào, bạn luôn có thể mở rộng trước:

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])}
}'

Sử dụng *trong một đặc tả định dạng cho phép bạn cung cấp độ dài trường động.


1
Không bao giờ nói là đã làm, nhưng nếu tôi muốn thỉnh thoảng hiển thị hai tệp cạnh nhau thì việc làm diff -y one.txt two.txttốt hơn là paste one.txt two.txtxóa các ký tự phụ khác biệt được hiển thị cùng sedvới việc viết / ghi nhớ một awktập lệnh là điều nhỏ nhặt . Ngay cả với cả hai hàm as .bash_rclâu hơn! = Tốt hơn, dễ đọc hơn, nhanh hơn .. lợi thế ở đây là gì?
Chris Seymour

2

loại bỏ tự động đếm độ dài trường khỏi câu trả lời của Barmar sẽ làm cho nó trở thành một lệnh ngắn hơn nhiều .... nhưng bạn vẫn cần ít nhất một tập lệnh để hoàn thành công việc, điều này không thể tránh khỏi cho dù bạn chọn phương pháp nào.

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

2

Nếu bạn muốn biết sự khác biệt thực tế giữa hai tệp cạnh nhau, hãy sử dụng diff -y:

diff -y file1.cf file2.cf

Bạn cũng có thể đặt chiều rộng đầu ra bằng -W, --width=NUMtùy chọn:

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

và để làm cho diffđầu ra cột của phù hợp với cửa sổ đầu cuối hiện tại của bạn:

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

2

Có một sedcách:

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

Dưới , bạn có thể sử dụng 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 /;"

(Tất nhiên giải pháp của @Hasturkun prchính xác nhất !) :

Lợi thế của sedhơnpr

Bạn có thể chọn chiều rộng và hoặc dải phân cách tinh vi:

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 /;"

Hoặc, đối với mẫu, để đánh dấu các dòng chứa 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"

sẽ kết xuất:

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

1

Tìm bên dưới một giải pháp dựa trên 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]

Thí dụ

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
táo
Lê
dòng dài hơn hai dòng cuối cùng
dòng cuối cùng
[root /]# cat /two.txt
Con cáo nâu nhanh nhẹn..
foo
quán ba
linux
[root@RHEL6-64 /]# diff -y one.txt two.txt
quả táo | Con cáo nâu nhanh nhẹn..
lê | foo
dòng dài hơn hai dòng cuối cùng | quán ba
dòng cuối cùng | linux

sdiffdiff -yđiều tôi thảo luận trong câu hỏi.
Chris Seymour

Vâng đúng ... nó đã được đề cập để hiển thị một thiết lập lệnh / cờ khác để thực hiện nó.
iAdhyan

Nhưng nó không trả lời các câu hỏi diffthêm các ký tự giữa hai tệp.
Chris Seymour

Tôi thấy thật đáng sợ khi bạn đang làm điều này với tư cách là người chủ ...
Pryftan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.