Làm thế nào để awk '! A [$ 0] ++' hoạt động?


39

Lớp lót này sẽ loại bỏ các dòng trùng lặp khỏi kiểu nhập văn bản mà không cần sắp xếp trước.

Ví dụ:

$ cat >f
q
w
e
w
r
$ awk '!a[$0]++' <f
q
w
e
r
$ 

Mã ban đầu tôi đã tìm thấy trên internets đọc:

awk '!_[$0]++'

Điều này thậm chí còn khó hiểu hơn đối với tôi khi tôi _có ý nghĩa đặc biệt trong awk, như trong Perl, nhưng hóa ra đó chỉ là một tên của một mảng.

Bây giờ, tôi hiểu logic đằng sau một lớp lót: mỗi dòng đầu vào được sử dụng làm khóa trong một mảng băm, do đó, khi hoàn thành, hàm băm chứa các dòng duy nhất theo thứ tự đến.

Điều tôi muốn tìm hiểu là cách chính xác ký hiệu này được diễn giải bởi awk. Ví dụ: dấu hiệu bang ( !) có nghĩa là gì và các yếu tố khác của đoạn mã này.

Làm thế nào nó hoạt động?


tiêu đề là sai lệch, nó phải là $ 0 (Không), không phải $ o (o).
Archemar

2
Vì nó là một hàm băm, nó không có thứ tự, vì vậy "theo thứ tự đến" không thực sự chính xác.
Kevin

Câu trả lời:


35

Hãy xem nào

 !a[$0]++

Đầu tiên

 a[$0]

chúng tôi xem giá trị của a[$0](mảng avới toàn bộ dòng đầu vào ( $0) là khóa).

Nếu nó không tồn tại ( !là phủ định trong thử nghiệm sẽ trở thành đúng)

 !a[$0]

chúng tôi in dòng đầu vào $0(hành động mặc định).

Ngoài ra, chúng tôi thêm một ( ++) vào a[$0], vì vậy lần sau !a[$0]sẽ đánh giá thành sai.

Hay đấy, tìm !! Bạn nên có một cái nhìn vào mã golf!


1
Vì vậy, bản chất là thế này: biểu thức trong các trích dẫn đơn được sử dụng awknhư là một thử nghiệm cho mỗi dòng đầu vào; mỗi khi thử nghiệm thành công awkthực hiện hành động trong các dấu ngoặc nhọn, mà khi bỏ qua là {print}. Cảm ơn!
Alexander Shcheblikin

3
@Archemar: Câu trả lời này là sai, xem của tôi.
cuonglm

@AlexanderShcheblikin awk, hành động mặc định là {print $0}. Điều này có nghĩa là bất cứ điều gì được đánh giá là đúng sẽ thực hiện điều này như mặc định. Vì vậy, ví dụ awk '1' filein tất cả các dòng, awk '$1' filein tất cả các dòng có trường đầu tiên không trống hoặc 0, v.v.
fedorqui

6
@Gnouc Tôi không thấy bất kỳ lỗi nghiêm trọng nào trong câu trả lời này. Nếu đó là những gì bạn đang đề cập, thì mức tăng thực sự được áp dụng sau khi giá trị của biểu thức được tính toán. Đúng là sự gia tăng xảy ra trước khi in, nhưng đó là một sự thiếu sót nhỏ không ảnh hưởng đến lời giải thích cơ bản.
Gilles 'SO- ngừng trở nên xấu xa'

1
Tôi tìm thấy lời giải thích tốt nhất cho một người mới hiểu ở đây trong quora: qr.ae/TUIVxM
GP92

29

Đây là cách xử lý:

  • a[$0]: nhìn vào giá trị của khóa $0, trong mảng kết hợp a. Nếu nó không tồn tại, tạo nó.

  • a[$0]++: tăng giá trị của a[$0], trả về giá trị cũ dưới dạng giá trị của biểu thức. Nếu a[$0]không tồn tại, trả về 0và tăng a[$0]lên 1( ++toán tử trả về giá trị số).

  • !a[$0]++: phủ định giá trị của biểu thức. Nếu a[$0]++trả về 0, toàn bộ biểu thức được ước tính là true, thực awkhiện hành động mặc định được thực hiện print $0. Nếu không, toàn bộ biểu thức được ước tính là sai, nguyên nhân awkkhông làm gì cả.

Tài liệu tham khảo:

Với gawk, chúng ta có thể sử dụng dgawk (hoặc awk --debugvới phiên bản mới hơn) để gỡ lỗi một gawktập lệnh. Đầu tiên, tạo một gawktập lệnh, được đặt tên test.awk:

BEGIN {                                                                         
    a = 0;                                                                      
    !a++;                                                                       
}

Sau đó chạy:

dgawk -f test.awk

hoặc là:

gawk --debug -f test.awk

Trong bảng điều khiển gỡ lỗi:

$ dgawk -f test.awk
dgawk> trace on
dgawk> watch a
Watchpoint 1: a
dgawk> run
Starting program: 
[     1:0x7fe59154cfe0] Op_rule             : [in_rule = BEGIN] [source_file = test.awk]
[     2:0x7fe59154bf80] Op_push_i           : 0 [PERM|NUMCUR|NUMBER]
[     2:0x7fe59154bf20] Op_store_var        : a [do_reference = FALSE]
[     3:0x7fe59154bf60] Op_push_lhs         : a [do_reference = TRUE]
Stopping in BEGIN ...
Watchpoint 1: a
  Old value: untyped variable
  New value: 0
main() at `test.awk':3
3           !a++;
dgawk> step
[     3:0x7fe59154bfc0] Op_postincrement    : 
[     3:0x7fe59154bf40] Op_not              : 
Watchpoint 1: a
  Old value: 0
  New value: 1
main() at `test.awk':3
3           !a++;
dgawk>

Bạn có thể thấy, Op_postincrementđã được thực hiện trước đó Op_not.

Bạn cũng có thể sử dụng sihoặc stepithay vì shoặc stepđể xem rõ hơn:

dgawk> si
[     3:0x7ff061ac1fc0] Op_postincrement    : 
3           !a++;
dgawk> si
[     3:0x7ff061ac1f40] Op_not              : 
Watchpoint 1: a
  Old value: 0
  New value: 1
main() at `test.awk':3
3           !a++;

3
@Archemar: Câu trả lời của bạn chỉ ra rằng !được áp dụng trước đây ++.
cuonglm

6
Câu trả lời này là sai. Sự gia tăng xảy ra sau khi kết quả của !toán tử được tính toán. Bạn đang nhầm lẫn quyền ưu tiên của toán tử ( !a[$0]++được phân tích cú pháp như !(a[$0]++)) với thứ tự đánh giá (việc gán giá trị mới a[$0]xảy ra sau khi giá trị của biểu thức đã được tính).
Gilles 'SO- ngừng trở nên xấu xa'

5
@Gnouc Nó nói ngay trong đoạn bạn trích dẫn, và nếu nó hoạt động theo cách bạn mô tả, mã này sẽ không có hiệu quả mong muốn. Đầu tiên giá trị !xđược tính, xgiá trị cũ ở đâu a[$0]. Sau đó a[$0]được đặt thành 1+x.
Gilles 'SO- ngừng trở nên xấu xa'

7
Tôi tin rằng phân tích của bạn về những gì awk làm là chính xác. Xin lỗi nếu tôi ngụ ý khác ngày hôm qua. Tuy nhiên, bài phê bình của bạn về câu trả lời của Archemar là sai. Archemar không hiểu nhầm quyền ưu tiên, bạn làm, bạn đang nhầm lẫn ưu tiên với thứ tự đánh giá (xem bình luận trước của tôi). Nếu bạn xóa bất kỳ đề cập nào về câu trả lời của Archemar, câu trả lời của bạn sẽ chính xác. Vì nó là, nó tập trung vào việc chứng minh Archemar sai, và đây không phải là trường hợp.
Gilles 'SO- ngừng trở nên xấu xa'

5
tốt, ít nhất bây giờ tôi biết về trình gỡ lỗi của awk ...
Archemar
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.