Điểm của việc sử dụng nhiều dấu chấm than trong sed là gì?


12

Tài liệu sed POSIX cho biết:

Một chức năng có thể được đi trước bởi một hoặc nhiều '!' các ký tự, trong trường hợp đó hàm sẽ được áp dụng nếu địa chỉ không chọn không gian mẫu. Không hoặc nhiều ký tự <blank> sẽ được chấp nhận trước dấu '!' Đầu tiên tính cách. Không xác định liệu các ký tự <blank> có thể theo dấu '!' ký tự và các ứng dụng tuân thủ sẽ không tuân theo dấu '!' ký tự có ký tự <blank>.

Vì vậy, với bất kỳ sed POSIX nào, chúng ta có thể:

sed -e '/pattern/!d' file

Nó giống như viết:

sed -e '/pattern/!!d' file

!!!dncác chấm than vết vẫn được ổn thôi (Tested với ba sedphiên bản từ gia truyền toolchest ). Tôi không thấy bất kỳ lợi ích nào giữa nhiều thay vì một câu cảm thán.

Tại sao thông số kỹ thuật cho phép cú pháp đó và nó hữu ích như thế nào trong ứng dụng thế giới thực?


Có vẻ như GNU sed không tuân thủ trong trường hợp này, nó sẽ phàn nàn nếu chúng ta sử dụng nhiều câu cảm thán:

$ sed -e '/pattern/!!d' file
sed: -e expression #1, char 11: multiple `!'s

2
FWIW: Trên OpenBSD !hoạt động như một sự chuyển đổi, /pattern/!!giống như /pattern//pattern/!!!giống như /pattern/!. Trên FreeBSD nhiều !cái giống như một cái duy nhất.
lcd047

2
Điểm của rất nhiều thứ trong thông số kỹ thuật là sedcác tập lệnh có thể được tạo ra . Với một POSIX sed, việc viết sedkịch bản cho một kịch bản sẽ là một vấn đề đơn giản . Và vì vậy, nếu bạn có một số kích hoạt cho một số trường hợp nên đánh dấu một địa chỉ !không xứng đáng với bất kỳ hành động nào của bạn, bạn thậm chí có thể kích hoạt nhiều lần cho cùng một địa điểm và vẫn đưa ra kết quả tương tự.
mikeerv

@cuonglm Không, chỉ có FreeBSD là. Các GNU, OpenBSD và NetBSD sedkhông.
lcd047

@ lcd047: vâng, tất nhiên rồi. Xin lỗi vì tiếng Anh của tôi không tốt. Tôi có nghĩa là nó không tuân thủ, là nó. Thật tốt khi biết điều đó. Nhưng điểm chính trong câu hỏi của tôi là làm thế nào cú pháp đó có thể hữu ích trong thế giới thực, với POSIX sed?
cuonglm

1
FWIW: một bản sửa lỗi cho điều này đã được cam kết trong OpenBSD-current.
lcd047

Câu trả lời:


5

sedAPI của nó là nguyên thủy - và đây là do thiết kế. Ít nhất, nó vẫn còn nguyên thủy bởi thiết kế - cho dù nó được thiết kế nguyên thủy khi bắt đầu tôi không thể nói. Trong hầu hết các trường hợp, việc viết một sedtập lệnh mà khi chạy sẽ tạo ra một sedtập lệnh khác thực sự là một vấn đề đơn giản. sedthường được áp dụng theo cách này bởi các bộ tiền xử lý macro như m4và / hoặc make.

.


Hãy xem xét các tập tin đầu vào sau đây:

cat <<"" >./infile
camel
cat dog camel
dog cat
switch
upper
lower

Nếu chúng ta muốn viết một sedkịch bản mà sẽ nối từ -case đến đuôi của từng thích hợp từ trong tập tin đầu vào ở trên chỉ nếu nó có thể được tìm thấy trên một dòng trong bối cảnh thích hợp , và chúng tôi mong muốn làm như vậy một cách hiệu quả càng tốt ( như là mục tiêu của chúng tôi, ví dụ, trong một hoạt động biên dịch) thì chúng tôi nên tránh áp dụng /regrec /s càng nhiều càng tốt.

Một điều chúng tôi có thể làm là chỉnh sửa trước tệp trên hệ thống của chúng tôi ngay bây giờ và không bao giờ gọi sedtất cả trong quá trình biên dịch. Nhưng nếu bất kỳ từ nào trong tệp nên hoặc không nên được đưa vào dựa trên cài đặt cục bộ và / hoặc tùy chọn thời gian biên dịch, thì làm như vậy có thể không phải là một lựa chọn thay thế mong muốn.

Một điều khác chúng ta có thể làm là xử lý tệp ngay bây giờ dựa trên biểu thức chính quy. Chúng tôi có thể sản xuất - và bao gồm trong phần tổng hợp của chúng tôi - một sedtập lệnh có thể áp dụng các chỉnh sửa theo số dòng - thường là một tuyến hiệu quả hơn nhiều trong thời gian dài.

Ví dụ:

n=$(printf '\\\n\t')
grep -En 'camel|upper|lower' <infile |
sed "   1i${n%?}#!/usr/heirloom/bin/posix2001/sed -nf
        s/[^:]*/:&$n&!n;&!b&$n&/;s/://2;\$a${n%?}q"'
        s/ *cat/!/g;s/ *dog/!/g
        s| *\([cul][^ ]*\).*|s/.*/\1-case/p|'

... viết đầu ra dưới dạng một sedtập lệnh và trông giống như ...

#!/usr/heirloom/bin/posix2001/sed -nf
:1
    1!n;1!b1
    1s/.*/camel-case/p
:2
    2!n;2!b2
    2!!s/.*/camel-case/p
:5
    5!n;5!b5
    5s/.*/upper-case/p
:6
    6!n;6!b6
    6s/.*/lower-case/p
q

Khi đầu ra đó được lưu vào một tệp văn bản thực thi trên máy của tôi có tên ./bang.sedvà chạy như thế nào ./bang.sed ./infile, đầu ra là:

camel-case
upper-case
lower-case

Bây giờ bạn có thể hỏi tôi ... Tại sao tôi muốn làm điều đó? Tại sao tôi không chỉ greplà trận đấu của neo ? Ai sử dụng lạc đà? Và với mỗi câu hỏi tôi chỉ có thể trả lời, tôi không biết ... vì tôi không biết. Trước khi đọc câu hỏi này, tôi chưa bao giờ nhận thấy cá nhân đa! yêu cầu phân tích cú pháp trong thông số kỹ thuật - Tôi nghĩ rằng đó là một cách bắt khá gọn gàng.

Các đa! điều đó ngay lập tức có ý nghĩa với tôi - phần lớn sedđặc tả được hướng tới các tập lệnh được phân tích cú pháp đơn giản và được tạo rased . Bạn có thể sẽ tìm thấy các \ndấu phân cách ewline cần thiết để [wr:bt{]có ý nghĩa hơn trong bối cảnh đó và nếu bạn giữ ý tưởng đó, bạn có thể hiểu rõ hơn về một số khía cạnh khác của thông số kỹ thuật - (chẳng hạn như :không chấp nhận địa chỉ và qtừ chối chấp nhận bất kỳ hơn 1) .

Trong ví dụ trên, chúng tôi viết ra một hình thức nhất định của sedkịch bản mà chỉ có thể từng được đọc một lần. Nếu bạn nhìn chăm chú vào nó, bạn có thể nhận thấy rằng khi sedđọc tệp chỉnh sửa, nó sẽ chuyển từ khối lệnh này sang khối lệnh tiếp theo - nó không bao giờ tách rời hoặc hoàn thành tập lệnh chỉnh sửa cho đến khi hoàn toàn thông qua tệp chỉnh sửa của nó.

Tôi xem xét rằng đa-! địa chỉ có thể hữu ích hơn trong bối cảnh đó so với một số địa chỉ khác, nhưng, thành thật mà nói, tôi không thể nghĩ đến một trường hợp duy nhất mà tôi có thể sử dụng nó rất tốt - và tôi sedrất nhiều. Tôi cũng nghĩ rằng đáng chú ý là cả GNU / BSD sedđều không xử lý được như đã chỉ định - đây có thể không phải là một khía cạnh của thông số kỹ thuật đang có nhiều nhu cầu, và vì vậy nếu một triển khai bỏ qua thì tôi nghi ngờ rất nghiêm trọng lỗi của họ @ box sẽ bị ảnh hưởng kết quả là khủng khiếp

Điều đó nói rằng, việc không xử lý việc này như được chỉ định một lỗi cho bất kỳ triển khai nào giả vờ tuân thủ và vì vậy tôi nghĩ rằng việc gửi email đến các hộp dev có liên quan được gọi là ở đây và tôi dự định sẽ làm như vậy nếu bạn không làm vậy.


1
Hiện đã được sửa trong OpenBSD-current.
lcd047

1
Nhiều người !sẽ bị xóa trong thông số tiếp theo , chuyện gì đang xảy ra ở đây!
cuonglm

@cuonglm - quá ít quá muộn, tôi đoán vậy. có lẽ tôi đã gần đến điểm hơn tôi nghĩ.
mikeerv

@cuonglm - tốt, ok, nhưng điều đó ... Được chấp nhận là Đánh dấu thậm chí có nghĩa là gì?
mikeerv

1
@mikeerv: câu trả lời đã giải thích điều kỳ diệu của tôi và cho tôi một cái nhìn khác với API sed. Nó có ý nghĩa với tôi!
cuonglm
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.