Cách xóa các dòng trống bắt đầu từ dòng 5


10

Tôi có cái này:

sed -i '/^$/d' temp_spec.rb

đó là tước dòng trống và hoạt động tốt. Làm thế nào tôi có thể làm cho nó chỉ làm điều này cho các dòng 5-999 (hoặc lý tưởng nhất là 5 đến cuối tập tin).

Tôi đã thử:

sed -n5,999 -i '/^$/d' temp_spec.rb
sed '5,999!d/^$/d' temp_spec.rb

nhưng không làm việc (không có lỗi).


Chỉ cần chắc chắn: Bạn có muốn giữ các dòng 1 đến 4, bất kể chúng có trống hay không, hoặc bạn muốn xóa các dòng 1 đến 4, bất kể chúng có trống hay không? (Cho đến nay, tôi đã giả sử trước đây, nhưng lệnh thứ hai bạn đã thử làm tôi tự hỏi.)
Uwe

Câu trả lời:


12

Nếu bạn muốn xóa tất cả các dòng trống bắt đầu bằng dòng 5 và giữ dòng 1 đến 4, bạn có thể sử dụng

sed -i '5,${;/^$/d;}' temp_spec.rb

Đây {là toán tử nhóm, vì vậy lệnh đầu tiên 5,${có nghĩa là "từ dòng 5 cho đến khi kết thúc đầu vào ( $) thực hiện các lệnh sau cho đến khi khớp }". Các lệnh giữa {}một lần nữa có thể được tiền tố bởi các địa chỉ, vì vậy lệnh bên trong /^$/dcó nghĩa là "nếu không có gì giữa đầu ( ^) và cuối ( $) của dòng, hãy xóa nó". Các lệnh sed có thể được phân tách bằng ;. (Đây là một tính năng được ghi chép kém của sed. Nó được hỗ trợ bởi hầu hết các triển khai sed, nhưng nó không hoàn toàn di động .) Theo ghi nhận của Hauke, phần ;sau {là tùy chọn; cái trước }là bắt buộc, mặc dù.

Nếu bạn muốn xóa tất cả các dòng trống bắt đầu bằng dòng 5 và cũng xóa các dòng 1 đến 4, thì dễ dàng hơn:

sed -i '1,4d;/^$/d' temp_spec.rb

Đẹp. Tôi không biết rằng địa chỉ có thể được lồng theo cách đó. Đối với tôi nó hoạt động mà không có hàng đầu ;, quá.
Hauke ​​Laging

Đúng, bạn nói đúng về người đầu tiên ;.
Uwe

@Hauke ​​Laging Bạn có thể tách các lệnh trong tập lệnh sed bằng ';' thay vì đặt chúng trên các dòng riêng biệt. Đó là một tính năng "không có giấy tờ".
Predrag Punosevac

4

Một tùy chọn khác sử dụng awk:

awk 'NR<5||/./'

2
sed '5,${s/^$//; t delete; b end; : delete; d; : end;}' temp_spec.rb

Chỉnh sửa 1:

Tôi phải giải thích điều này, do đó ...

Điều này là phức tạp không cần thiết. Tôi không biết rằng phạm vi địa chỉ được cho phép trong {}. Vì vậy, tôi đã phải thể hiện "xóa các dòng trống" khác nhau. Lệnh cốt lõi là tcách của sed if ... then. Tsẽ dễ dàng hơn nhưng chỉ có sẵn cho GNU sed. Tôi trích dẫn trang người đàn ông:

nhãn t: Nếu như /// đã 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.

Tôi lạm dụng smệnh lệnh nổi tiếng . Nó sẽ không thay thế bất cứ điều gì mà chỉ kiểm tra xem dòng có trống không. Vì vậy, nó thay thế một dòng trống bằng một dòng trống (có thể sử dụng bất cứ thứ gì thay thế khi dòng bị xóa bằng mọi cách).

Nếu sđã thực hiện "thay thế" thì dòng trống. Trong trường hợp đó, lệnh dsẽ được thực thi. Nếu không thì không có gì để làm Vì tkhông nhảy trong trường hợp có shành động, tôi cần lệnh nhánh bđể nhảy đến cuối tập lệnh. : labellà mục tiêu chi nhánh. Giống như gotohồi đó trong thời kỳ đen tối (khi sed được phát minh ... te-hee).

Một tùy chọn khác là s"thay thế" tất cả các dòng không trống, làm cho lệnh sphức tạp hơn nhưng phần còn lại dễ dàng hơn:

sed '5,${s/^\(..*\)$/\1/; t end; d; : end;}' input

^..*$có nghĩa là "dòng không trống" và \1có nghĩa là "nội dung của dấu ngoặc đầu tiên".


Một chút giải thích cho lợi ích của OP (Tôi có thể cảm thấy não của họ đang cố bò ra ngoài bằng tai khi đọc điều này ...)
vonbrand
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.