Trong các bình luận cho câu hỏi này, một trường hợp đã được đưa ra trong đó các triển khai sed khác nhau không đồng ý với một chương trình khá đơn giản và chúng tôi (hoặc ít nhất là tôi) không thể xác định được đặc tả thực sự cần gì cho nó.
Vấn đề là hành vi của một phạm vi bắt đầu tại một dòng bị xóa:
1d;1,2d
Có nên xóa dòng 2 ngay cả khi bắt đầu phạm vi bị xóa trước khi đến lệnh đó không? Kỳ vọng ban đầu của tôi là "không" phù hợp với BSD sed, trong khi GNU sed nói "có" và việc kiểm tra văn bản đặc tả không giải quyết được hoàn toàn vấn đề.
Phù hợp với kỳ vọng của tôi là (ít nhất) macOS và Solaris sed
và BSD sed
. Không đồng ý là (ít nhất) GNU và Busybox sed
, và nhiều người ở đây. Hai cái đầu tiên được chứng nhận SUS trong khi những cái khác có khả năng phổ biến rộng rãi hơn. Hành vi nào là đúng?
Các văn bản đặc điểm kỹ thuật cho các phạm vi hai địa chỉ nói:
Sau đó, tiện ích sed sẽ áp dụng theo thứ tự tất cả các lệnh có địa chỉ chọn không gian mẫu đó, cho đến khi lệnh bắt đầu chu trình tiếp theo hoặc thoát.
và
Lệnh chỉnh sửa có hai địa chỉ sẽ chọn phạm vi bao gồm từ không gian mẫu đầu tiên khớp với địa chỉ đầu tiên thông qua không gian mẫu tiếp theo khớp với địa chỉ thứ hai. [...] Bắt đầu từ dòng đầu tiên theo phạm vi đã chọn, sed sẽ tìm lại địa chỉ đầu tiên. Sau đó, quá trình sẽ được lặp lại.
Có thể cho rằng, dòng 2 là trong "phạm vi bao gồm từ không gian mô hình đầu tiên mà phù hợp với địa chỉ đầu tiên thông qua không gian mô hình tiếp theo phù hợp với thứ hai", bất kể điểm khởi đầu đã bị xóa. Mặt khác, tôi dự kiến người đầu tiên d
sẽ chuyển sang chu kỳ tiếp theo và không cho phạm vi bắt đầu. Các triển khai được chứng nhận UNIX ™ thực hiện những gì tôi mong đợi, nhưng có khả năng không phải là những gì đặc tả bắt buộc.
Một số thí nghiệm minh họa theo, nhưng câu hỏi chính là: những gì nên sed
làm gì khi một loạt bắt đầu trên một dòng bị xóa?
Thí nghiệm và ví dụ
Một minh chứng đơn giản cho vấn đề này là vấn đề này in ra các bản sao thêm của các dòng thay vì xóa chúng:
printf 'a\nb\n' | sed -e '1d;1,2p'
Điều này cung cấp sed
hai dòng đầu vào a
và b
. Chương trình thực hiện hai điều:
Xóa dòng đầu tiên với
1d
. Cácd
lệnh sẽXóa không gian mẫu và bắt đầu chu kỳ tiếp theo. và
- Chọn phạm vi của các dòng từ 1 đến 2 và in rõ ràng chúng ra, ngoài việc in tự động mỗi dòng nhận được. Do đó, một dòng trong phạm vi sẽ xuất hiện hai lần.
Kỳ vọng của tôi là điều này sẽ in
b
chỉ, với phạm vi không áp dụng vì 1,2
không bao giờ đạt được trong dòng 1 (vì d
đã nhảy sang chu kỳ / dòng tiếp theo) và do đó, phạm vi bao gồm không bao giờ bắt đầu, trong khi a
đã bị xóa. Các Unix phù hợp sed
của macOS và Solaris 10 tạo ra đầu ra này, cũng như không phải POSIX sed
trong Solaris và BSD sed
nói chung.
GNU sed, mặt khác, in
b
b
chỉ ra rằng nó đã giải thích phạm vi. Điều này xảy ra cả trong chế độ POSIX và không. Sedy của Busybox có hành vi tương tự (nhưng không phải hành vi giống hệt nhau, vì vậy dường như đó không phải là kết quả của mã được chia sẻ).
Thử nghiệm thêm với
printf 'a\nb\nc\nd\ne\n' | sed -e '2d;2,/c/p'
printf 'a\nb\nc\nd\ne\n' | sed -e '2d;2,/d/p'
thấy rằng nó xuất hiện để xử lý một phạm vi bắt đầu từ một dòng bị xóa như thể nó bắt đầu trên dòng sau . Điều này có thể nhìn thấy vì /c/
không khớp để kết thúc phạm vi. Sử dụng /b/
để bắt đầu phạm vi không hoạt động giống như 2
.
Ví dụ làm việc ban đầu tôi đang sử dụng là
printf '%s\n' a b c d e | sed -e '1{/a/d;};1,//d'
như một cách để xóa tất cả các dòng cho đến /a/
khớp đầu tiên , ngay cả khi đó là trên dòng đầu tiên (thứ mà GNU sed sẽ sử dụng 0,/a/d
cho - đây là một biểu hiện tương thích POSIX đã cố gắng).
Có ý kiến cho rằng điều này thay vào đó nên xóa tối đa trận đấu thứ hai/a/
nếu dòng đầu tiên khớp (hoặc toàn bộ tệp nếu không có kết quả khớp thứ hai), điều này có vẻ hợp lý - nhưng một lần nữa, chỉ GNU sed mới làm điều đó. Cả hai sản phẩm sed của macOS và Solaris
b
c
d
e
vì điều đó, như tôi mong đợi (GNU sed tạo ra đầu ra trống để loại bỏ phạm vi bị hủy bỏ; Busybox sed chỉ in d
và e
, rõ ràng là không có vấn đề gì). Nói chung, tôi cho rằng họ đã vượt qua các bài kiểm tra tuân thủ chứng nhận có nghĩa là hành vi của họ là đúng, nhưng đủ người đã đề nghị khác là tôi không chắc chắn, văn bản đặc tả không hoàn toàn thuyết phục và bộ kiểm tra không thể hoàn toàn toàn diện.
Rõ ràng ngày nay nó không thực sự di động để viết mã đó với sự không nhất quán, nhưng về mặt lý thuyết nó phải tương đương ở mọi nơi với nghĩa này hay nghĩa khác. Tôi nghĩ rằng đây là một lỗi, nhưng tôi không biết phải báo cáo việc triển khai nào. Quan điểm của tôi hiện tại là hành vi của GNU và Busybox sed không phù hợp với đặc điểm kỹ thuật, nhưng tôi có thể bị nhầm lẫn về điều đó.
POSIX yêu cầu gì ở đây?
ed
, bỏ quased
hoàn toàn?