Chênh lệch chuỗi trong Bash


110

Tôi đang cố gắng tìm cách xác định sự khác biệt giữa hai chuỗi trong tập lệnh của mình. Tôi có thể dễ dàng làm điều này với diff hoặc comm, nhưng tôi không xử lý các tệp và tôi không muốn xuất chúng ra tệp, hãy so sánh và đọc lại.

Tôi thấy rằng comm, diff, cmp đều cho phép chuyển hai tệp HOẶC một tệp và đầu vào tiêu chuẩn - Tôi đoán điều đó tốt nếu tôi không muốn xuất hai tệp ... nhưng nó vẫn hơi tệ.

Tôi đã suy nghĩ về việc tôi có thể sử dụng grep hoặc biểu thức chính quy - nhưng tôi đoán là không.


1
bạn thực sự muốn làm gì?

Bạn có thể sử dụng substring thao tác và được xây dựng trong các hoạt động thử nghiệm với thay đổi IFS để so sánh, nhưng bạn sẽ cần phải biết nếu bạn muốn so sánh từng ký tự, từng chữ, từng dòng, bỏ qua khoảng trắng ...
technosaurus

Câu trả lời:


198

Sử dụng diffhoặc comhoặc bất cứ điều gì bạn muốn:

diff  <(echo "$string1" ) <(echo "$string2")

Câu hỏi thường gặp về Greg's Bash: Quy trình thay thế

hoặc với một đường ống được đặt tên

mkfifo ./p
diff - p <<< "$string1" & echo "$string2" > p

Câu hỏi thường gặp về Greg's Bash: Làm việc với các đường ống được đặt tên

Đường ống được đặt tên còn được gọi là FIFO.

Riêng -nó là cho đầu vào tiêu chuẩn.

<<< là một "chuỗi ở đây".

&giống như ;nhưng đặt nó trong nền


5
+1 cho câu trả lời đúng. +1 để giải thích tuyệt vời về các ký hiệu. Ngoài ra, Câu hỏi thường gặp về Bash của Greg đã được chuyển đến: mywiki.wooledge.org Các liên kết cho các trang trên hiện có tại mywiki.wooledge.org/ProcessSubstitutionmywiki.wooledge.org/BashFAQ/085
timemachine3030

cám ơn! và ngoài ra, điều này sẽ hiển thị các bộ mô tả tệp độngFUNC(){ echo "$@"; "$@"; }; FUNC diff <(echo a) <(echo b);
Aquarius Power

Tôi đã tìm kiếm điều đó để so sánh hai shasums. Không chắc liệu có cách nào thanh lịch hơn để làm điều đó, nhưng nó hoạt động.
fuma

Điều này dường như hoạt động nếu có nhiều dòng trong $ string1 và $ string2, và diff xuất ra các dòng đã được cộng hoặc trừ. Điều gì sẽ xảy ra nếu chuỗi là một dòng đơn và dòng và có một số khác biệt giữa hai chuỗi?
alpha_989

@ alpha_989, đây là câu trả lời của bạn: $ diff <(echo "Here are the letters in String One.") <(echo "Here are the characters in String Two.") \n 1c1 \n < Here are the letters in String One. \n --- \n > Here are the characters in String Two. \nSử dụng đường dẫn cũng tương tự, ngoại trừ nó hiển thị số tiến trình, bắt đầu bằng dấu 1c1sau $và đợi cho đến khi bạn nhấn <kbd> Enter <kbd> (hoặc bạn có thể thực hiện các lệnh khác ...)
bballdave025,

19

Nhắc tôi câu hỏi này: Làm thế nào bạn có thể khác biệt hai đường ống dẫn trong Bash?

Nếu bạn đang ở trong một phiên bash, bạn có thể thực hiện:

diff <cmd1 <cmd2
diff <(foo | bar) <(baz | quux)

với <việc tạo các đường ống được đặt tên ẩn danh - được quản lý bởi bash - vì vậy chúng được tạo và hủy tự động, không giống như các tệp tạm thời.

Vì vậy, nếu bạn quản lý để cô lập hai chuỗi khác nhau của mình như một phần của lệnh (grep, awk, sed, ...), bạn có thể làm - ví dụ - một cái gì đó như:

diff < grep string1 myFile < grep string2 myFile

(nếu bạn giả sử bạn có trong các dòng tệp của mình như string1=very_complicated_valuevà a string2=another_long_and_complicated_value': mà không biết định dạng bên trong của tệp, tôi không thể đề xuất một lệnh chính xác)


13

Tôi thích cmpvà tính năng Thay thế Quy trình của bash:

$ cmp -bl <(echo -n abcda) <(echo -n aqcde)
  2 142 b    161 q
  5 141 a    145 e

Nói ở vị trí 2, ab xảy ra cho vị trí đầu tiên, nhưng aq cho vị trí thứ hai. Ở vị trí số 5, một sự khác biệt khác đang diễn ra. Chỉ cần thay thế các chuỗi đó bằng các biến và bạn đã hoàn tất.


Điều này chỉ hoạt động khi các chuỗi có cùng độ dài!
strpeter

11

Giả sử bạn có ba chuỗi

a="this is a line"
b="this is"
c="a line"

Để xóa tiền tố b khỏi a

echo ${a#"$b"}  # a line

Để xóa hậu tố c khỏi a

echo ${a%"$c"}  # this is

2
Tôi đoán đây là cách làm điều đó. Nó hoạt động tốt. Tuy nhiên, cú pháp đó hơi khó nắm bắt.
Mikael Roos

@MikaelRoos Đồng ý. Dễ đọc hơn (đối với tôi) sẽ là sử dụng sed: echo "$a" | sed "s!^$b!!g" (Tôi đã hoán đổi dấu phân tách sed tiêu chuẩn / for! Trong trường hợp các biến đang được xử lý là đường dẫn. Ngoài ra, bạn có thể sử dụng chuỗi here thay vì echo:. sed ... <<< $a)
ACK_stoverflow

0

Một vi dụ khac:

before="184613 102050 83756 63054"
after="184613 102050 84192 83756 63054"

comm -23 <(tr ' ' $'\n' <<< $after | sort) <(tr ' ' $'\n' <<< $before | sort)

Kết quả đầu ra

84192

Câu trả lời gốc ở đây

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.