Sed có thể loại bỏ các ký tự dòng mới 'nhân đôi' không?


25

Tôi có một tài liệu với rất nhiều dòng trống.

Làm thế nào tôi có thể loại bỏ chúng khi có 2 hoặc nhiều hơn với nhau.

Tôi đã thử sed "s/\n\n//"tập tin nhưng nó không hoạt động. Không có lỗi.


3
Tôi có đọc chính xác cho bạn không nếu bạn không muốn xóa tất cả các dòng trống, nhưng chỉ khi đó là hai hoặc nhiều hơn. Vì vậy, không phải dòng trống đơn ?
Runium

1
Và nếu đó là hai hoặc nhiều dòng thì thực sự tất cả chúng sẽ bị xóa hay chỉ là một?
Hauke ​​Laging

Câu trả lời:


42

Chỉ để xóa các dòng trống:

sed  '/^$/d'

sedđược định hướng theo dòng, do đó, suy nghĩ theo nghĩa "2 hoặc nhiều hơn một byte cụ thể" hoạt động trừ khi byte đó là một dòng mới. Sau đó, bạn phải nghĩ ra một cái gì đó hoạt động cho toàn bộ dòng.


Tất nhiên! +1 cho sự thanh lịch đơn giản.
terdon

2
sedcó khả năng xử lý một số dòng thông qua tính năng "không gian mẫu" / "không gian giữ". Nhưng tôi cảm thấy điều đó quá phức tạp. ;-)
Hauke ​​Laging

Điều này sẽ không hoạt động như mong muốn nếu ký tự đầu tiên của tệp là một dòng mới.
Chris Xuống

1
Để làm cho nó hoạt động khi ký tự đầu tiên là một dòng mới (nếu đó thực sự là một yêu cầu), thì bạn có thể kèm theo lệnh với một địa chỉ phủ định 1!(khớp với tất cả ngoại trừ dòng 1), do đó : sed '1!{/^$/d'}.
Toby Speight

1
@AaronFranke - có, nhưng đó là một khía cạnh về cách các vỏ Linux xử lý chuyển hướng '>'. Shell nhìn vào dòng lệnh, thấy một chuyển hướng '>' của thiết bị xuất chuẩn vào một tệp, tạo tệp đó và chỉ sau đó chạy sed. Tạo một tệp về cơ bản sẽ xóa bất kỳ tệp hiện có cùng tên. sed '/^&/d' file.txt > otherfile.txtsẽ làm việc.
Bruce Ediger

24

Không cần sed. grepsẽ làm:

grep .

(đó là grepSPC, dấu chấm, khớp với bất kỳ dòng nào chứa ít nhất một ký tự).

Ngoài ra còn có:

tr -s '\n'

(ép bất kỳ chuỗi ký tự dòng mới thành một).

Như Chris đã lưu ý, cả hai đều không tương đương vì loại bỏ các dòng trống (như giải pháp đầu tiên ở trên và hầu hết các câu trả lời khác tập trung vào đây) không giống như việc ép các chuỗi ký tự dòng mới theo yêu cầu trong trường hợp dòng đầu tiên trống như nó chỉ mất một ký tự dòng mới hàng đầu để làm cho dòng đầu tiên trống.


2
Điều này sẽ không hoạt động như mong muốn nếu ký tự đầu tiên của tệp là một dòng mới: spunge.us/FLAJ
Chris Down

7

sedkhông phải là công cụ tốt nhất cho điều đó, vì nó dựa trên dòng và được coi \nlà ký tự cuối dòng, điều này trở nên phức tạp.Đã thấy câu trả lời của @Bruce Ediger sedcó thể là công cụ hoàn hảo cho công việc, tuy nhiên, đây là một số tùy chọn khác:

  1. Perl

    perl -ne 'print if /./' file.txt
    

    hoặc là

    perl -pe '$/=""; s/\n+/\n/;' file.txt 
    

    Cảm ơn @ruakh đã khiến tôi đi và đọc :

    $ /

    Dấu tách bản ghi đầu vào, dòng mới theo mặc định. Điều này ảnh hưởng đến ý tưởng của Perl về "đường kẻ" là gì. Hoạt động như biến RS của awk, bao gồm xử lý các dòng trống làm đầu cuối nếu được đặt thành chuỗi null (một dòng trống không thể chứa bất kỳ khoảng trắng hoặc tab nào). Bạn có thể đặt chuỗi đó thành một chuỗi nhiều ký tự để khớp với một đầu cuối nhiều ký tự hoặc không xác định để đọc đến cuối tệp. Đặt nó thành "\ n \ n" có nghĩa là một cái gì đó hơi khác so với cài đặt thành "", nếu tệp chứa các dòng trống liên tiếp. Đặt thành "" sẽ coi hai hoặc nhiều dòng trống liên tiếp thành một dòng trống đơn. Đặt thành "\ n \ n" sẽ mù quáng cho rằng ký tự đầu vào tiếp theo thuộc về đoạn tiếp theo, ngay cả khi đó là một dòng mới.

  2. gawk / awk

    awk '$1' file.txt
    

    Điều đó sẽ làm việc cho ví dụ được đăng nhưng như @Stephane Chazelas đã chỉ ra, nó cũng sẽ xóa các dòng có trường đầu tiên "trông giống như" 0. Điều này mạnh mẽ hơn:

    awk NF file.txt
    

Đối với Perl, perl -pe 's/\n+/\n/ file.txtsẽ làm, phân tách bản ghi đầu vào là không liên quan cho việc sử dụng này.
vonbrand

@vonbrand không, perl -pehoặc perl -nelàm việc theo dòng. \n+sẽ không bao giờ khớp bởi vì nó chỉ được áp dụng trên một dòng duy nhất. Đó là lý do tại sao bạn cần phải thiết lập $/hoặc sử dụng -0ti để xóa toàn bộ tệp : perl -0pe 's/\n+/\n/' file.
terdon

6

Bạn có ý nghĩa gì để loại bỏ? xóa trùng lặp (nhiều dòng trống thành một) hoặc xóa tất cả?

Nếu bạn muốn loại bỏ trùng lặp, đây là phương pháp sử dụng sed:

sed '$!N; /^\(.*\)\n\1$/!P; D'

Nó mô phỏng uniqlệnh.

Sự lựa chọn tốt nhất là sử dụng awk:

awk NF <filename>

Phần sednày hoạt động rất tốt! Đề nghị này là một câu trả lời tốt nhất.
Akito

2

Đối với hầu hết các câu trả lời này, trước tiên cần phải xóa khoảng trắng ở cuối. Loại bỏ các dòng mới tăng gấp đôi sẽ loại bỏ tất cả các dòng trống. (Nghĩ về điều này).

Theo nghĩa đen, OP muốn "tất cả các dòng trống được xóa khỏi một tệp nếu có bất kỳ dòng trống lặp lại nào".

Người dùng thông thường muốn "chỉ xóa các dòng trống trùng lặp".

Để làm điều này, trước tiên hãy vạch ra dấu vết trắng và đường ống mặc dù con mèo

sed  s/[[:space:]]*$// | cat -s

Tuy nhiên, điều này sẽ không loại bỏ một dòng trống hàng đầu hoặc dấu vết thừa.


Downvote, nhưng điều này rõ ràng hoạt động? Miễn bình luận ?
mckenzm 7/2/2015

1
Tôi ủng hộ bạn vì ... bạn biết ... trả lời câu hỏi. =) Tôi không thể tin rằng phản hồi của Bruce Ediger đã được nâng cấp khi nó xóa mọi dòng trống. Nếu ai đó hỏi làm thế nào để xóa các dòng trống trùng lặp, tôi không thể tưởng tượng bất kỳ kịch bản nào trong đó xóa tất cả các dòng trống sẽ là một giải pháp chấp nhận được. Nhưng sao cũng được. Nhân tiện, có một trang trên trang web dành cho sed bao gồm điều này: gnu.org/software/sed/manual/sed.html#cat-_002ds
Todd Walton

2

Nếu bạn muốn giữ một dòng trống duy nhất cho bất kỳ chuỗi trống nào, bạn có thể làm:

sed -e '/./b' -e :n -e 'N;s/\n$//;tn'

1
Đây là câu trả lời duy nhất (bên cạnh cat -s) thực sự hoàn thành chính xác những gì câu hỏi được hỏi khi tôi hiểu nó. (Và nó tốt hơn là cat -svì tôi có thể sử dụng sed -ivới nó.)
Matthew

-2

Hãy thử sed -e 's#\\n\\n#\\n#g' input.file > output.filesử dụng /cả hai như dấu tách trường và một phần của biểu thức chính quy của bạn có thể là vấn đề.


2
Chỉ cần tạo một vòng xoáy với một trong các tệp của tôi chứa các dòng mới gấp đôi và gấp ba trong một chuỗi. Không làm việc gì cho tôi cả.
cú pháp

-3

Sử dụng lệnh này:

tr -s '\r' '\n'

vâng, câu trả lời của họ không làm việc cho tôi.
meo

5
AFAIK câu trả lời này là không chính xác. Tôi khuyên bạn nên xóa nó.
zuazo

oh, đó là vì tập tin của tôi chứa rất nhiều dòng mới và trả lại vận chuyển thực sự. 0x0d0a
meo

2
Trên thực tế, lệnh loại bỏ các dòng lặp đi lặp lại với các cửa sổ cuối dòng. Kiểm tra với echo -e 'one\r\n\r\n\r\n\rtwo'| tr -s '\r' '\n'. Lệnh trsẽ dịch tất cả \rsang \nvà sau đó sẽ ép tất cả \nthành chỉ một. Vì vậy, nó hoạt động, không biết phải làm gì với thực tế là điều này áp dụng cho windows chứ không phải UNIX.
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.