Cách sử dụng sed để xóa n dòng cuối cùng của tệp


148

Tôi muốn xóa một số n dòng từ cuối tập tin. Điều này có thể được thực hiện bằng cách sử dụng sed?

Ví dụ: để xóa các dòng từ 2 đến 4, tôi có thể sử dụng

$ sed '2,4d' file

Nhưng tôi không biết số dòng. Tôi có thể xóa dòng cuối cùng bằng cách sử dụng

$sed $d file

nhưng tôi muốn biết cách để loại bỏ n dòng từ cuối. Xin vui lòng cho tôi biết làm thế nào để làm điều đó bằng cách sử dụng sed hoặc một số phương pháp khác.


2
@arashkordi: sử dụng số đếm từ đầu tệp chứ không phải dưới cùng.
am

Câu hỏi liên quan về siêu nhân .
Thor

//, Có lẽ nên xem xét lại câu hỏi để làm cho nó chung chung hơn chỉ sed ?
Nathan Basan

1
sed $d filetrả về một lỗi Thay vào đó, $ d nên nằm trong dấu ngoặc kép, như thế này:sed '$d' file
Akronix

Câu trả lời:


221

Tôi không biết sed, nhưng nó có thể được thực hiện với head:

head -n -2 myfile.txt

19
+1 cho đơn giản. Lệnh sed tương đương là mông xấu xí: sed -e :a -e '$d;N;2,5ba' -e 'P;D' file( ,5cho 5 dòng cuối cùng).
Marc B

62
Lưu ý rằng điều này hoạt động với một số phiên bản head, nhưng không phải là tiêu chuẩn. Thật vậy, tiêu chuẩn cho headcác tiểu bang:The application shall ensure that the number option-argument is a positive decimal integer.
William Pursell

21
Để thêm vào câu trả lời của @ WilliamPursell ... Trên trình bao mặc định của Mac OS, điều này không hoạt động.
JDS

7
Cũng không có trên BSD, nhưng câu hỏi được gắn thẻ Linux.
AMS

3
trừ đi 1, bởi vì, ngoài osx, điều này không hiệu quả với tôi trên Ubuntu14 -head: illegal line count -- -2
Michael Durrant

30

Nếu hardcoding n là một tùy chọn, bạn có thể sử dụng các cuộc gọi tuần tự để sed. Ví dụ: để xóa ba dòng cuối cùng, hãy xóa ba dòng cuối cùng:

sed '$d' file | sed '$d' | sed '$d'

2
Điều này, cộng với -i để chỉnh sửa tệp tại chỗ thay vì bỏ nó vào thiết bị xuất chuẩn, đã làm việc cho tôi.
WAF

27

Từ sed một lớp lót :

# delete the last 10 lines of a file
sed -e :a -e '$d;N;2,10ba' -e 'P;D'   # method 1
sed -n -e :a -e '1,10!{P;N;D;};N;ba'  # method 2

Có vẻ là những gì bạn đang nới lỏng.


@Thor bạn có thể thay đổi số lượng dòng được xóa khỏi tệp bằng cách thay đổi 10trong'$d;N;2,10ba'
Alexej Magura

1
@AlexejMagura: Tôi đã bình luận về một phiên bản trước của câu trả lời.
Thor

22

Một funny & đơn giản sedtacgiải pháp:

n=4
tac file.txt | sed "1,$n{d}" | tac

GHI CHÚ

  • dấu ngoặc kép "là cần thiết cho shell để đánh giá $nbiến trongsed lệnh. Trong dấu ngoặc đơn, không có nội suy sẽ được thực hiện.
  • taclà một catđảo ngược, xemman 1 tac
  • các {}tại sedđang có để tách $n& d(nếu không muốn nói, vỏ cố gắng để không tồn tại Nội suy $ndbiến)

7
fyi no tacon osx
Michael Durrant

1
@MichaelDurrant port info coreutils| | brew info coreutils;
lên tiếng

19

Sử dụng sed, nhưng để shell thực hiện phép toán, với mục tiêu là sử dụng dlệnh bằng cách đưa ra một phạm vi (để xóa 23 dòng cuối cùng):

sed -i "$(($(wc -l < file)-22)),\$d" file

Để xóa 3 dòng cuối cùng, từ trong ra ngoài:

$(wc -l < file)

Cung cấp số lượng dòng của tệp: nói 2196

Chúng tôi muốn xóa 23 dòng cuối cùng, vì vậy đối với bên trái hoặc phạm vi:

$((2196-22))

Gives: 2174 Do đó, sed ban đầu sau khi giải thích hệ vỏ là:

sed -i '2174,$d' file

Với -iviệc thực hiện chỉnh sửa tại chỗ, tập tin hiện có 2173 dòng!

Nếu bạn muốn lưu nó vào một tệp mới, mã là:

sed -i '2174,$d' file > outputfile

15

Bạn có thể sử dụng đầu cho việc này.

Sử dụng

$ head --lines=-N file > new_file

Trong đó N là số dòng bạn muốn xóa khỏi tệp.

Nội dung của tệp gốc trừ N dòng cuối cùng hiện có trong new_file


8

Để hoàn thiện tôi muốn thêm giải pháp của mình. Tôi đã kết thúc việc này với tiêu chuẩn ed:

ed -s sometextfile <<< $'-2,$d\nwq'

Thao tác này sẽ xóa 2 dòng cuối bằng cách sử dụng chỉnh sửa tại chỗ (mặc dù nó không sử dụng một tập tin tạm thời trong /tmp!!)


5

Để cắt các tệp rất lớn thực sự tại chỗ, chúng tôi có truncatelệnh. Nó không biết về các dòng, nhưng tail+ wccó thể chuyển đổi các dòng thành byte:

file=bigone.log
lines=3
truncate -s -$(tail -$lines $file | wc -c) $file

Có một điều kiện cuộc đua rõ ràng nếu tập tin được viết cùng một lúc. Trong trường hợp này có thể tốt hơn để sử dụng head- nó đếm byte từ đầu tệp (IO đĩa tâm), vì vậy chúng tôi sẽ luôn cắt ngắn trên ranh giới dòng (có thể nhiều dòng hơn dự kiến ​​nếu tệp được ghi chủ động):

truncate -s $(head -n -$lines $file | wc -c) $file

Tiện dụng một lớp lót nếu bạn không đăng nhập cố gắng đặt mật khẩu thay cho tên người dùng:

truncate -s $(head -n -5 /var/log/secure | wc -c) /var/log/secure

4

Điều này có thể làm việc cho bạn (GNU sed):

sed ':a;$!N;1,4ba;P;$d;D' file

Đẹp. Bạn đã bỏ lỡ dấu nháy đơn kết thúc ( ').
Thor

xin lỗi vì nhận xét quá muộn nhưng tôi đã thử và (đã quảng cáo cho AIX / posix của tôi) nó đã thất bại trong việc in tất cả trừ dòng cuối cùng. Đọc mã, tôi không hiểu tại sao bốn dòng cuối cùng được gỡ bỏ, các vòng lặp rõ ràng là trên 4 dòng đầu tiên để chắc chắn nó loop sau một d, Dhoặc Pvới GNU sed và không phải trên phiên bản posix. Có vẻ như các dòng không được in sau Dvà giữ trong bộ đệm làm việc cho một vòng lặp mới mà không chuyển đến 'kết thúc' của dòng hành động.
NeronLeVelu

@NeronLeVelu chương trình đọc trong một cửa sổ gồm 4 dòng vào không gian mẫu và sau đó nối thêm dòng tiếp theo và in dòng đầu tiên cho đến khi đến cuối tệp nơi nó xóa các dòng còn lại.
potong

@potong có, tôi đã thử nghiệm trên một chiếc sed GNU và nó giữ bộ đệm giữa các dòng nơi posix dỡ nó sau khi Dtạo hiệu ứng ngược lại.
NeronLeVelu

4

Hầu hết các câu trả lời ở trên dường như yêu cầu các lệnh / phần mở rộng GNU:

    $ head -n -2 myfile.txt
    -2: Badly formed number

Đối với một giải pháp khả thi hơn một chút:

     perl -ne 'push(@fifo,$_);print shift(@fifo) if @fifo > 10;'

HOẶC LÀ

     perl -ne 'push(@buf,$_);END{print @buf[0 ... $#buf-10]}'

HOẶC LÀ

     awk '{buf[NR-1]=$0;}END{ for ( i=0; i < (NR-10); i++){ print buf[i];} }'

Trong đó "10" là "n".


2

Với câu trả lời ở đây, bạn đã học được rằng sed không phải là công cụ tốt nhất cho ứng dụng này.

Tuy nhiên tôi nghĩ có một cách để làm điều này trong việc sử dụng sed; ý tưởng là nối thêm N dòng để giữ khoảng trống cho đến khi bạn có thể đọc mà không cần nhấn EOF. Khi EOF được nhấn, in nội dung của không gian giữ và thoát.

sed -e '$!{N;N;N;N;N;N;H;}' -e x

Lệnh sed ở trên sẽ bỏ qua 5 dòng cuối cùng.


2

Hãy thử lệnh sau:

n = line number
tail -r file_name | sed '1,nd' | tail -r

Hãy giải thích làm thế nào điều này hoạt động. FYI - để khởi tạo các biến shell, chúng ta không nên có khoảng trống xung quanh =.
tiền mã hóa

@codeforester Dòng đầu tiên là một nhận xét tôi đoán. Anh ta chỉ sử dụng tail -rnơi mà những người khác đã sử dụng tacđể đảo ngược trật tự, và làm cho các ndòng cuối cùng trở thành các ndòng đầu tiên.
Nicolas Melay

2

Nó có thể được thực hiện trong 3 bước:

a) Đếm số lượng dòng trong tệp bạn muốn chỉnh sửa:

 n=`cat myfile |wc -l`

b) Trừ số đó số dòng cần xóa:

 x=$((n-3))

c) Nói với sed để xóa từ số dòng đó ( $x) đến cuối:

 sed "$x,\$d" myfile

Toán xấu. Nếu bạn phải xóa 3 dòng, sau đó trừ 3 nhưng THÊM 1. Với toán học của bạn, nếu tệp có 10 dòng, 10 - 3 = 7 và bạn đang sử dụng sedđể xóa các dòng 7 đến 10, đó là 4 dòng, không phải 3
mathguy

1

Bạn có thể lấy tổng số dòng wc -l <file>và sử dụng

head -n <total lines - lines to remove> <file>


1

Điều này sẽ xóa 3 dòng cuối cùng khỏi file:

for i in $(seq 1 3); do sed -i '$d' file; done;


1
Đây là cách quá đắt đối với các tệp lớn - toàn bộ tệp phải được đọc và viết lại n lần! Và như nhiều dĩa cho sed.
tiền mã hóa

trong khi điều này có thể không phải là giải pháp hiệu quả nhất, nó vẫn là một cách đơn giản và dễ hiểu nhất
Dharam

0

Tôi thích giải pháp này;

head -$(gcalctool -s $(cat file | wc -l)-N) file

Trong đó N là số dòng cần loại bỏ.


0
sed -n ':pre
1,4 {N;b pre
    }
:cycle
$!{P;N;D;b cycle
  }' YourFile

phiên bản posix


0

Để xóa 4 dòng cuối cùng:

$ nl -b a file | sort -k1,1nr | sed '1, 4 d' | sort -k1,1n | sed 's/^ *[0-9]*\t//'   

hơi nặng (đặc biệt là về tài nguyên) so với đầu. Ít nhất là tac file | sed '1,4d' | tacvì sắp xếp sau đó loại bỏ tiền tố rất nhiều nguồn tài nguyên.
NeronLeVelu

@NeronLeVelu bạn đúng nhưng không có taclệnh nào là một số hệ thống (ví dụ FreeBSD?)
mstafreshi 23/1/2015

0

Tôi đã đưa ra điều này, trong đó n là số dòng bạn muốn xóa:

count=`wc -l file`
lines=`expr "$count" - n`
head -n "$lines" file > temp.txt
mv temp.txt file
rm -f temp.txt

Đó là một vòng xoay nhỏ, nhưng tôi nghĩ nó dễ theo dõi.

  1. Đếm số lượng dòng trong tệp chính
  2. Trừ số dòng bạn muốn xóa khỏi số đếm
  3. In ra số lượng dòng bạn muốn giữ và lưu trữ trong tệp tạm thời
  4. Thay thế tệp chính bằng tệp tạm thời
  5. Xóa tệp tạm thời

0

Để xóa N dòng cuối cùng của tệp, bạn có thể sử dụng cùng một khái niệm về

$ sed '2,4d' file

Bạn có thể sử dụng kết hợp với lệnh tail để đảo ngược tệp: nếu N là 5

$ tail -r file | sed '1,5d' file | tail -r > file

Và cách này cũng chạy khi head -n -5 filelệnh không chạy (như trên máy mac!).


-2

Điều này sẽ loại bỏ 12 dòng cuối cùng

sed -n -e :a -e '1,10!{P;N;D;};N;ba'

1
Một chút giải thích sẽ giúp xin vui lòng.
Richard Wiseman
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.