Ý nghĩa của: a; $! N; trong một lệnh sed?


10
$ (echo hello; echo there) | sed ':a;$!N;s/\n/string/;ta'
hellostringthere

sedLệnh trên thay thế ký tự dòng mới bằng chuỗi "chuỗi". Nhưng tôi không biết ý nghĩa của :a;$!N;s/\n/string/;tacác trích dẫn. Tôi biết phần giữa s/\n/string/. Nhưng tôi không biết chức năng của phần đầu tiên ( :a;$!N;) và phần cuối ( ta).



Còn phần cuối thì sao?
Avinash Raj

Lệnh "t" phân nhánh thành nhãn có tên nếu lệnh thay thế cuối cùng sửa đổi không gian mẫu.
xiaodongjie

Câu trả lời:


17

Đây là những sedlệnh được thừa nhận là khó hiểu . Cụ thể (từ man sed):

: nhãn
         Nhãn cho các lệnh b và t.

nhãn t
         Nếu as /// đã thực hiện thay thế thành công kể từ khi dòng đầu vào cuối cùng được đọc và kể từ lệnh t hoặc T cuối cùng, sau đó phân nhánh thành nhãn; nếu nhãn bị bỏ qua, nhánh đến cuối tập lệnh.

n N Đọc / nối dòng đầu vào tiếp theo vào không gian mẫu.

Vì vậy, tập lệnh bạn đã đăng có thể được chia thành (khoảng trắng được thêm vào để dễ đọc):

sed ':a;  $!N;  s/\n/string/;  ta'
     ---  ----  -------------  --
      |     |        |          |--> go back (`t`) to `a`
      |     |        |-------------> substitute newlines with `string`
      |     |----------------------> If this is not the last line (`$!`), append the 
      |                              next line to the pattern space.
      |----------------------------> Create the label `a`.

Về cơ bản, những gì nó đang làm có thể được viết bằng mã giả như

while (not end of line){
    append current line to this one and replace \n with 'string'
}

Bạn có thể hiểu điều này tốt hơn một chút với một ví dụ đầu vào phức tạp hơn:

$ printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;$!N;s/\n/string/;ta'
line1stringline2stringline3stringline4stringline5

Tôi không thực sự chắc chắn tại sao !$cần thiết. Theo như tôi có thể nói, bạn có thể nhận được cùng một đầu ra với

printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;N;s/\n/string/;ta'

1
! $ Là không khớp với dòng mới nhất, IMO.
Braiam

@Braiam không quá chắc chắn về điều đó, $!không phải vậy !$. Tuy nhiên, nó cũng có thể !Nvà không $!.
terdon

Tôi đã cố gắng để phân tích trang texinfo nhưng không tìm thấy tài liệu tham khảo để không !Nhay $!. Vì vậy, tôi vẫn giữ suy nghĩ của mình là tìm kiếm nếu dòng cuối cùng là dòng mới hoặc EOF.
Braiam

4
Tôi cố gắng nghĩ về $!một 'phạm vi' địa chỉ với một toán tử bổ sung postfix - vì vậy $!N(làm Nmọi nơi trừ địa chỉ $) thực sự là cú pháp giống như một cái gì đó giống như m,n!d(xóa mọi thứ trừ các dòng mđến n).
Steel

:gotonhãn tương tự , và trên thực tế :từng là nhãn goto trong vỏ Thompson, vì vậy nó quen thuộc với mọi người trước đây khi sử dụng cả vỏ sed và vỏ Thompson
Sergiy Kolodyazhnyy

0

Tôi gửi câu trả lời này kể từ khi tôi nhìn thấy rất nhiều nhầm lẫn về lý do tại sao dòng cuối cùng bị loại trừ khi thực hiện N(thông qua các dòng địa chỉ chuỗi $!) và vì OP đã nhầm lẫn về ý nghĩa của :a;$!N; trong một lệnh sed , không chỉ trong các một cụ ông gửi .

Chà, lợi ích của việc sử dụng $!Nthay vì Nkhông rõ ràng trong các ví dụ được đề xuất (bởi OP và @terdon), vì không có lệnh "quan trọng" (tiếp tục đọc) được thực hiện trên dòng cuối cùng sau Nlệnh. (Thật vậy, kết quả là như nhau nếu một dải địa chỉ tắt.)

Trong một ví dụ phức tạp hơn (ví dụ, thay thế this sentencetrong một tệp, với hai từ đôi khi xuất hiện trên một dòng và một số lần khác trên hai dòng), ngoại trừ dòng cuối cùng cho Nlệnh có thể rất quan trọng! Nếu dòng cuối cùng không được loại trừ, khi thực hiện Ntrên nó, sedchạm EOFvà thoát ngay lập tức, ngăn chặn tất cả các lệnh tiếp theo (cũng như các lệnh phân nhánh, cụ thể tb) được thực thi.

Trong các ví dụ quá đơn giản được hiển thị, chúng ta có thể loại bỏ một cách an toàn $!sedthất bại trong việc thực thi Nvà trả về vì slệnh bị hủy sẽ không làm gì nếu nó được thực thi, vì không \nkhớp.

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.