Làm cách nào để tập tin khác bỏ qua các bình luận (dòng bắt đầu bằng #)?


55

Tôi có hai tệp cấu hình, bản gốc từ trình quản lý gói và một tệp tùy chỉnh được tự sửa đổi. Tôi đã thêm một số ý kiến ​​để mô tả hành vi.

Làm thế nào tôi có thể chạy difftrên các tập tin cấu hình, bỏ qua các ý kiến? Một dòng nhận xét được xác định bởi:

  • khoảng trắng hàng đầu tùy chọn (tab và dấu cách)
  • dấu băm ( #)
  • bất cứ nhân vật nào khác

Biểu thức chính quy (đơn giản nhất) bỏ qua yêu cầu đầu tiên sẽ là #.*. Tôi đã thử tùy chọn --ignore-matching-lines=RE( -I RE) của GNU diff 3.0, nhưng tôi không thể làm cho nó hoạt động với RE đó. Tôi cũng đã thử .*#.*.*\#.*không gặp may. Nghĩa đen là đặt dòng ( Port 631) REkhông khớp với bất cứ thứ gì, cũng không giúp đặt RE giữa các dấu gạch chéo.

Như đề xuất trong hương vị regex của công cụ khác có vẻ thiếu? , Tôi đã thử grep -G:

grep -G '#.*' file

Điều này có vẻ phù hợp với các ý kiến, nhưng nó không hoạt động diff -I '#.*' file1 file2.

Vì vậy, nên sử dụng tùy chọn này như thế nào? Làm thế nào tôi có thể diffbỏ qua một số dòng nhất định (trong trường hợp của tôi, ý kiến)? Vui lòng không đề xuất greping tệp và so sánh các tệp tạm thời.


12
Các -Itùy chọn gây ra một khối sẽ bị loại bỏ chỉ khi tất cả các dòng của nó phù hợp với regexp. Vì vậy, bạn có thể bỏ qua thay đổi chỉ nhận xét theo cách đó, nhưng không thay đổi nhận xét gần thay đổi không nhận xét.
Gilles 'SO- đừng trở nên xấu xa'

@Gilles: Cảm ơn, bây giờ tôi hiểu tại sao diff -Ikhông hành xử như tôi mong đợi. Tôi đã cập nhật câu trả lời của mình với một ví dụ làm rõ hành vi này cho tôi.
Lekensteyn

Câu trả lời:


49

Theo Gilles, -Itùy chọn chỉ bỏ qua một dòng nếu không có gì khác bên trong tập hợp đó ngoại trừ kết quả khớp -I. Tôi đã không hoàn toàn nhận được nó cho đến khi tôi thử nghiệm nó.

Các bài kiểm tra

Ba tệp có liên quan đến thử nghiệm của tôi:
Tệp test1:

    text

Tập tin test2:

    text
    #comment

Tập tin test3:

    changed text
    #comment

Các lệnh:

$ # comparing files with comment-only changes
$ diff -u -I '#.*' test{1,2}
$ # comparing files with both comment and regular changes
$ diff -u -I '#.*' test{2,3}
--- test2       2011-07-20 16:38:59.717701430 +0200
+++ test3       2011-07-20 16:39:10.187701435 +0200
@@ -1,2 +1,2 @@
-text
+changed text
 #comment

Cách khác

Vì cho đến nay vẫn chưa có câu trả lời giải thích cách sử dụng -Itùy chọn một cách chính xác, tôi sẽ cung cấp một giải pháp thay thế hoạt động trong bash shell:

diff -u -B <(grep -vE '^\s*(#|$)' test1)  <(grep -vE '^\s*(#|$)' test2)
  • diff -u - khác biệt thống nhất
    • -B - bỏ qua các dòng trống
  • <(command)- một tính năng bash được gọi là thay thế quá trình mở ra một bộ mô tả tệp cho lệnh, điều này loại bỏ sự cần thiết của một tệp tạm thời
  • grep - lệnh in các dòng (không) khớp với mẫu
    • -v - hiển thị các dòng không khớp
    • E - sử dụng các biểu thức chính quy mở rộng
    • '^\s*(#|$)' - một biểu thức chính quy phù hợp với các bình luận và các dòng trống
      • ^ - khớp với đầu dòng
      • \s* - khớp khoảng trắng (tab và dấu cách) nếu có
      • (#|$) khớp với dấu băm hoặc cách khác là kết thúc một dòng

6

Thử:

diff -b -I '^#' -I '^ #' file1 file2

Xin lưu ý rằng regex phải khớp với dòng tương ứng trong cả hai tệp và nó khớp với mọi dòng thay đổi trong hunk để hoạt động, nếu không nó vẫn sẽ hiển thị sự khác biệt.

Sử dụng dấu ngoặc đơn để bảo vệ mẫu khỏi mở rộng shell và để thoát các ký tự dành riêng cho biểu thức chính quy (ví dụ: ngoặc).

Chúng ta có thể đọc trong diffutilshướng dẫn:

Tuy nhiên, -Ichỉ bỏ qua việc chèn hoặc xóa các dòng có chứa biểu thức chính quy nếu mỗi dòng thay đổi trong hunk (mọi phần chèn và mọi phần xóa) khớp với biểu thức chính quy.

Nói cách khác, đối với mỗi thay đổi không thể bỏ qua, hãy diffin toàn bộ các thay đổi trong vùng lân cận, bao gồm cả những thay đổi không thể biết được. Bạn có thể chỉ định nhiều hơn một biểu thức chính quy cho các dòng bỏ qua bằng cách sử dụng nhiều hơn một -Itùy chọn. diffcố gắng khớp từng dòng với từng biểu thức chính quy, bắt đầu với biểu thức cuối cùng được đưa ra.

Hành vi này cũng được giải thích tốt bởi armel ở đây .

Liên quan: Làm thế nào tôi có thể thực hiện một diff mà bỏ qua tất cả các ý kiến?


2

Sau khi tìm kiếm trên web, cách khác của Lekensteyn là cách tốt hơn tôi tìm thấy.

Nhưng tôi muốn sử dụng đầu ra khác nhau như một bản vá ... và có một vấn đề vì số dòng được lưu giữ vì "grep -v".

Vì vậy, tôi có mục đích cải thiện dòng lệnh này:

diff -u -B <(sed 's/^[[:blank:]]*#.*$/ /' file1)  <(sed 's/^[[:blank:]]*#.*$/ /' file2)

Nó không hoàn hảo nhưng số dòng được giữ trong tệp vá.

Tuy nhiên, nếu một dòng mới được thêm vào thay vì dòng bình luận ... bình luận sẽ được tạo ra một Hunk FAILED khi vá như chúng ta có thể thấy dưới đây.

File test1:
  text
  #comment
  other text
File test2:
  text
  new line here
  #comment changed
  other text changed

kiểm tra ngay lệnh của chúng tôi

$ echo -e "#!/usr/bin/sed -f\ns/^[[:blank:]]*#.*$/ /" > outcom.sed
$ echo "diff -u -B <(./outcom.sed \$1)  <(./outcom.sed \$2)" > mydiff.sh
$ chmod +x mydiff.sh outcom.sed
$ ./mydiff.sh file1 file2 > file.dif
$ cat file.dif
--- /dev/fd/63  2014-08-23 10:05:08.000000000 +0200
+++ /dev/fd/62  2014-08-23 10:05:08.000000000 +0200
@@ -1,2 +1,3 @@
 text
+new line

-other text
+other text changed

/ dev / fd / 62 & / dev / fd / 63 là tệp được tạo bởi quá trình thay thế. Dòng giữa "+ dòng mới" và "văn bản khác" là ký tự không gian mặc định được xác định trong biểu thức sed của chúng tôi để thay thế các nhận xét.

Và bây giờ, những gì đang đến khi chúng tôi áp dụng bản vá này:

$ patch -p0 file1 < file.dif 
patching file file1
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED -- saving rejects to file file1.rej

Giải pháp là không sử dụng định dạng diff hợp nhất mà không có -u

$ echo "diff -B <(./outcom.sed \$1)  <(./outcom.sed \$2)" > mydiff.sh
$ ./mydiff.sh file1 file2 > file.dif
$ cat file.dif
1a2
> new line
3c4
< other text
---
> other text changed
$ patch -p0 file1 < file.dif 
patching file file1
$ cat file1
text
new line
#comment
other text changed

bây giờ vá tập tin làm việc tập tin (không có bảo hành kết quả trong quá trình khác biệt rất phức tạp).


Khác biệt thống nhất của bạn không áp dụng do sự khác biệt bối cảnh. Bạn có thể sử dụng diff -U0 one twođể vô hiệu hóa bối cảnh. Để vá lỗi, có một loạt các công cụ có thể phù hợp hơn như kdiff3.
Lekensteyn

Cảm ơn bạn đã -U0lựa chọn để vô hiệu hóa bối cảnh. Lưu ý: kdiff3 là một công cụ đồ họa. Tôi cần công cụ tự động để quản lý các thuộc tính hợp nhất git.
chỉnh

vimdiffhỗ trợ sáp nhập ba chiều, có thể đáng xem xét.
Lekensteyn

nói chính xác hơn, tôi cần một công cụ tập lệnh để tự động hóa quá trình hợp nhất git với các ngoại lệ trong tập lệnh sql. kdiff3 và vimdiff là các công cụ tương tác, không thể sử dụng trong trường hợp của tôi.
chỉnh

1

Tôi thường bỏ qua sự lộn xộn này bởi một trong hai:

  • Tạo các phiên bản không nhận xét bằng cách sử dụng grep -v "^#" | cat -svà phân biệt chúng hoặc ...
  • Sử dụng vim -dđể xem các tập tin. Cú pháp tô sáng quan tâm đến việc đưa ra nhận xét so với sự khác biệt không bình luận khá rõ ràng. Điểm nổi bật khác biệt của sự khác biệt trong dòng để bạn có thể thấy những giá trị hoặc phần nào của các giá trị đã được thay đổi trong nháy mắt làm cho điều này trở thành yêu thích của tôi.

0

Đây là những gì tôi sử dụng để xóa tất cả các dòng nhận xét - cả những dòng bắt đầu bằng một tab hoặc dấu cách - và các dòng trống:

egrep -v "^$|^[[:space:]]*#" /path/to/file

hoặc bạn có thể làm

sed -e '/^#.*/d' -e 's/#.*//g' | cat -s
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.