tra-loi-cau-hoi-phat-trien-web.com

Sự khác biệt giữa hai danh sách sử dụng Bash

Ok, tôi có hai danh sách liên quan trên hộp linux của mình trong các tệp văn bản:

 /tmp/oldList
 /tmp/newList

Tôi cần so sánh các danh sách này để xem dòng nào đã được thêm và dòng nào đã bị xóa. Sau đó tôi cần lặp lại các dòng này và thực hiện các hành động trên chúng dựa trên việc chúng được thêm hoặc xóa.

Làm thế nào để tôi làm điều này trong bash?

23
exvance

Sử dụng lệnh comm(1) để so sánh hai tệp. Cả hai đều cần được sắp xếp, điều mà bạn có thể làm trước nếu chúng lớn hoặc bạn có thể thực hiện nội tuyến với thay thế bash process .

comm có thể kết hợp các cờ -1, -2-3 chỉ ra tệp nào để chặn dòng từ (duy nhất cho tệp 1, duy nhất cho tệp 2 hoặc chung cho cả hai).

Để có được các dòng chỉ trong tập tin cũ:

comm -23 <(sort /tmp/oldList) <(sort /tmp/newList)

Để nhận các dòng chỉ trong tệp mới:

comm -13 <(sort /tmp/oldList) <(sort /tmp/newList)

Bạn có thể đưa dữ liệu đó vào vòng lặp while read để xử lý từng dòng:

while read old ; do
    ...do stuff with $old
done < <(comm -23 <(sort /tmp/oldList) <(sort /tmp/newList))

và tương tự cho các dòng mới.

58
camh

Lệnh diff sẽ thực hiện việc so sánh cho bạn.

ví dụ., 

$ diff /tmp/oldList /tmp/newList

Xem liên kết trang người đàn ông ở trên để biết thêm thông tin. Điều này sẽ chăm sóc phần đầu tiên của bạn trong vấn đề của bạn.

5
Levon

Cân nhắc sử dụng Ruby nếu tập lệnh của bạn cần dễ đọc.

Để có được các dòng chỉ trong tập tin cũ:

Ruby -e "puts File.readlines('/tmp/oldList') - File.readlines('/tmp/newList')"

Để nhận các dòng chỉ trong tệp mới:

Ruby -e "puts File.readlines('/tmp/newList') - File.readlines('/tmp/oldList')"

Bạn có thể đưa nó vào vòng lặp đọc trong khi xử lý từng dòng:

while read old ; do
  ...do stuff with $old
done < Ruby -e "puts File.readlines('/tmp/oldList') - File.readlines('/tmp/newList')"
3
Nowaker

Điều này đã cũ, nhưng để hoàn thiện chúng ta nên nói rằng nếu bạn có một bộ thực sự lớn, giải pháp nhanh nhất sẽ là sử dụng diff để tạo tập lệnh và sau đó lấy nguồn, như sau:

#!/bin/bash

line_added() {
   # code to be run for all lines added
   # $* is the line 
}

line_removed() {
   # code to be run for all lines removed
   # $* is the line 
}

line_same() {
   # code to be run for all lines at are the same
   # $* is the line 
}

cat /tmp/oldList | sort >/tmp/oldList.sorted
cat /tmp/newList | sort >/tmp/newList.sorted

diff >/tmp/diff_script.sh \
    --new-line-format="line_added %L" \
    --old-line-format="line_removed %L" \
    --unchanged-line-format="line_same %L" \
    /tmp/oldList.sorted /tmp/newList.sorted

source /tmp/diff_script.sh

Các dòng thay đổi sẽ xuất hiện dưới dạng xóa và thêm. Nếu bạn không thích điều này, bạn có thể sử dụng định dạng --changed-group-format. Kiểm tra trang hướng dẫn khác.

1
Costa Tsaousis

Bạn đã thử diff

$ diff /tmp/oldList /tmp/newList

$ man diff
0
ssedano

Tôi thường sử dụng:

diff /tmp/oldList /tmp/newList | grep -v "Common subdirectories"

Tùy chọn grep -v đảo ngược trận đấu:

-v, --invert-match [.__.] Các dòng được chọn là những dòng không khớp với bất kỳ pat nào được chỉ định - [.__.].

Vì vậy, trong trường hợp này, nó sẽ lấy kết quả diff và bỏ qua những kết quả phổ biến.

0
Nathan