Xóa (các) số dòng cụ thể khỏi tệp văn bản bằng sed?


235

Tôi muốn xóa một hoặc nhiều số dòng cụ thể khỏi một tệp. Làm thế nào tôi có thể làm điều này bằng cách sử dụng sed?


1
Bạn có thể đưa ra một ví dụ cụ thể hơn về những gì bạn muốn? Làm thế nào bạn sẽ quyết định những dòng để loại bỏ?
Mark Byers

Có thể xem thêm stackoverflow.com/questions/13272717/ và chỉ áp dụng ngược lại (in nếu khóa không nằm trong mảng kết hợp).
tripleee

Câu trả lời:


373

Nếu bạn muốn xóa các dòng 5 đến 10 và 12:

sed -e '5,10d;12d' file

Điều này sẽ in kết quả ra màn hình. Nếu bạn muốn lưu kết quả vào cùng một tệp:

sed -i.bak -e '5,10d;12d' file

Điều này sẽ sao lưu tệp lên đến file.bakvà xóa các dòng đã cho.

Lưu ý: Số dòng bắt đầu từ 1. Dòng đầu tiên của tệp là 1, không phải 0.


31
Không phải tất cả các bản hòa âm đều có gnu sed với "-i". Đừng phạm sai lầm khi quay lại "tập tin sed cmd> tập tin", điều này sẽ xóa sạch tập tin của bạn.
khen ngợi

4
Nếu tôi muốn xóa dòng thứ 5 đến dòng cuối cùng thì sao?
Jürgen Paul

14
@WearetheWorldsed -e '5,$d' file
Brian Campbell

1
@BrianCampbell Tôi nên làm gì để chỉ xóa một dòng cụ thể ??
Kanagavelu Sugumar

14
@KanagaveluSugumar sed -e '5d' file. Cú pháp là <address><command>; trong đó <address>có thể là một dòng giống như 5hoặc một phạm vi dòng như thế 5,10, và lệnh dxóa dòng hoặc dòng đã cho. Các địa chỉ cũng có thể là biểu thức chính quy hoặc ký hiệu đô la $cho biết dòng cuối cùng của tệp.
Brian Campbell

50

Bạn có thể xóa một dòng đơn cụ thể với số dòng của nó bằng cách

sed -i '33d' file

Thao tác này sẽ xóa dòng trên số dòng 33 và lưu tệp đã cập nhật.


1
Trong trường hợp của tôi "sed" đã loại bỏ một dòng sai. Vì vậy, tôi sử dụng phương pháp này : sed -i '0,/<TARGET>/{/<NEW_VALUE>/d;}' '<SOME_FILE_NAME>'. Cảm ơn!
Eduardo Lucio

Tương tự ở đây, tôi đã viết một vòng lặp và kỳ lạ là một số tệp bị mất dòng chính xác nhưng một số tệp cũng bị mất một dòng khác, không có manh mối gì đã xảy ra. (GNU / Linux bash4.2) Lệnh awk bên dưới hoạt động tốt trong vòng lặp
FatihSarigol

Hãy thực sự cẩn thận khi sử dụng sort -r nếu bạn đang xóa khỏi danh sách các dòng, nếu không chiếc sed đầu tiên của bạn sẽ thay đổi số dòng của mọi thứ khác! ...
Konchog

Để nhận xét về các dòng sai bị xóa trong một vòng lặp: hãy chắc chắn bắt đầu với số dòng lớn nhất, nếu không, mỗi dòng bị xóa sẽ bù lại số thứ tự dòng
Skippy le Grand Gourou

25

và awk là tốt

awk 'NR!~/^(5|10|25)$/' file

2
Lưu ý: Dòng awk đó hoạt động với tôi đáng tin cậy hơn so với biến thể sed (giữa OS-X và Ubuntu Linux)
Jay Taylor

3
Lưu ý rằng điều này không xóa bất cứ điều gì trong tập tin. Nó chỉ in các tập tin mà không có những dòng này để xuất bản. Vì vậy, bạn cũng cần chuyển hướng đầu ra sang tệp tạm thời, sau đó di chuyển tệp tạm thời để thay thế tệp gốc.
mivk


6

Đây thường là một triệu chứng của một antipotype. Công cụ tạo ra các số dòng cũng có thể được thay thế bằng một công cụ xóa các dòng ngay lập tức. Ví dụ;

grep -nh error logfile | cut -d: -f1 | deletelines logfile

(nơi mà deletelinestiện ích bạn đang tưởng tượng bạn cần) cũng giống như

grep -v error logfile

Phải nói rằng, nếu bạn đang ở trong một tình huống mà bạn thực sự cần phải thực hiện nhiệm vụ này, bạn có thể tạo một sedtập lệnh đơn giản từ tệp số dòng. Hài hước (nhưng có lẽ hơi khó hiểu) bạn có thể làm điều này với sed.

sed 's%$%d%' linenumbers

Điều này chấp nhận một tệp số dòng, mỗi dòng trên một dòng và tạo ra, trên đầu ra tiêu chuẩn, cùng một số dòng được dnối sau mỗi dòng. Đây là một sedtập lệnh hợp lệ , mà chúng ta có thể lưu vào một tệp hoặc (trên một số nền tảng) sang một sedthể hiện khác :

sed 's%$%d%' linenumbers | sed -f - logfile

Trên một số nền tảng, sed -fkhông hiểu đối số tùy chọn -có nghĩa là đầu vào tiêu chuẩn, do đó bạn phải chuyển hướng tập lệnh sang tệp tạm thời và dọn sạch nó khi bạn hoàn thành hoặc có thể thay thế dấu gạch ngang bằng /dev/stdinhoặc/proc/$pid/fd/1 nếu hệ điều hành của bạn (hoặc trình bao ) có cái đó.

Như mọi khi, bạn có thể thêm -itrước -ftùy chọn để sedchỉnh sửa tệp đích, thay vì tạo kết quả trên đầu ra tiêu chuẩn. Trên các nền tảng * BSDish (bao gồm cả OSX), bạn cũng cần cung cấp một đối số rõ ràng -i; một thành ngữ phổ biến là cung cấp một đối số trống; -i ''.


Tôi không hoàn toàn đồng ý với "triệu chứng của một antipotype". Các loại tệp dựa trên đánh dấu (ví dụ: XML hoặc JSON) yêu cầu các dòng cụ thể ở cuối để là các tệp hợp lệ. Trong trường hợp đó, đó thường là cách tiếp cận hợp lý nhất để loại bỏ các dòng đó, đưa vào tệp những gì bạn muốn thêm và sau đó thêm lại các dòng đó, bởi vì đặt các dòng ở giữa có thể tốn nhiều công sức hơn và chống lại mong muốn tiềm năng để tránh các công cụ bổ sung như sed càng nhiều càng tốt.
Egor Hans

Tôi hoàn toàn không hiểu bạn đang tưởng tượng loại kịch bản nào. Có những kịch bản trong đó đây là một cách tiếp cận hợp pháp nhưng phần lớn các trường hợp tôi đã thấy là những người mới làm ít nhiều chính xác những gì ví dụ đầu tiên của tôi chứng minh. (Có lẽ chúng đến từ một số ngôn ngữ cấp thấp thực sự và được sử dụng để phân chia vấn đề của họ vượt qua cấp độ phân tử, bởi vì bạn phải ở asm hoặc C.)
tripleee

Loại bỏ những thứ theo số dòng từ XML hoặc JSON âm thanh extermely giòn, nếu không hoàn toàn nguy hiểm.
tripleee

Về cơ bản, điều tôi muốn nói là, với tư cách là người tạo ra một tệp như vậy, bạn biết những gì phải có ở cuối tài liệu (nghĩa là tập hợp dấu ngoặc / dấu ngoặc vuông trong vài dòng cuối cùng cho JSON hoặc chính xác đóng các thẻ cho XML). Nhận thức được điều đó, cách tiếp cận đơn giản nhất để mở rộng một tài liệu như vậy là 1) xóa vài dòng cuối cùng, 2) thêm nội dung mới, 3) thêm lại vài dòng cuối cùng. Bằng cách này, tài liệu có thể hợp lệ cả trước và sau khi nó được mở rộng, mà không cần phải tìm cách thêm dòng giữa tài liệu.
Egor Hans

1
Cho đến nay, đây là câu trả lời duy nhất với một giải pháp thích hợp cho một số lượng lớn các dòng (tức là được cung cấp bởi một tệp). Và lời nói đầu cũng có ý nghĩa. Nó xứng đáng được nâng cao hơn. BTW, nếu bạn muốn in các dòng thay vì xóa chúng, hãy sử dụng pthay vì dcùng với tùy chọn -n(nó sẽ không hoạt động mà không hoạt động -n!dcũng không hoạt động).
Skippy le Grand Gourou

2

Tôi muốn đề xuất một khái quát với awk.

Khi tệp được tạo bởi các khối có kích thước cố định và các dòng cần xóa được lặp lại cho mỗi khối, awk có thể hoạt động tốt theo cách như vậy

awk '{nl=((NR-1)%2000)+1; if ( (nl<714) || ((nl>1025)&&(nl<1029)) ) print  $0}'
 OriginFile.dat > MyOutputCuttedFile.dat

Trong ví dụ này, kích thước của khối là 2000 và tôi muốn in các dòng [1..713] và [1026..1029].

  • NR là biến được sử dụng bởi awk để lưu trữ số dòng hiện tại.
  • % đưa ra phần còn lại (hoặc mô đun) của phép chia hai số nguyên;
  • nl=((NR-1)%BLOCKSIZE)+1Ở đây chúng ta viết vào biến nl số dòng bên trong khối hiện tại. (xem bên dưới)
  • ||&&là toán tử logic ORAND .
  • print $0 viết dòng đầy đủ

Why ((NR-1)%BLOCKSIZE)+1:
(NR-1) We need a shift of one because 1%3=1, 2%3=2, but 3%3=0.
  +1   We add again 1 because we want to restore the desired order.

+-----+------+----------+------------+
| NR  | NR%3 | (NR-1)%3 | (NR-1)%3+1 |
+-----+------+----------+------------+
|  1  |  1   |    0     |     1      |
|  2  |  2   |    1     |     2      |
|  3  |  0   |    2     |     3      |
|  4  |  1   |    0     |     1      |
+-----+------+----------+------------+


2
Tôi ngưỡng mộ cách bạn sống với cái tên gây ra sự điên rồ của bạn.
Jukka Dahlbom
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.