Câu hỏi Xóa các dòng trong một tệp văn bản chứa một chuỗi cụ thể


Làm thế nào tôi sẽ sử dụng sed để xóa tất cả các dòng trong một tập tin văn bản có chứa một chuỗi cụ thể?


1324
2018-03-23 19:46


gốc




Các câu trả lời:


Để xóa dòng và in đầu ra thành tiêu chuẩn:

sed '/pattern to match/d' ./infile

Để sửa đổi trực tiếp tệp:

sed -i '/pattern to match/d' ./infile

Để trực tiếp sửa đổi tệp (và tạo bản sao lưu):

sed -i.bak '/pattern to match/d' ./infile

Đối với người dùng Mac OS X:

sed -i '' '/pattern/d' ./infile

1988
2018-03-23 19:48



Cảm ơn, nhưng nó không có vẻ để xóa nó từ tập tin nhưng chỉ in ra các nội dung tập tin văn bản mà không có chuỗi đó. - A Clockwork Orange
@A Clockwork: có, bạn cần phải chuyển hướng đầu ra hoặc vào một tệp mới với một cái gì đó như sed '/pattern to match/d' ./infile > ./newfilehoặc nếu bạn muốn thực hiện chỉnh sửa tại chỗ thì bạn có thể thêm -i cờ để sed như trong sed -i '/pattern to match/d' ./infile. Lưu ý rằng -i cờ yêu cầu GNU sed và không di động - SiegeX
Đối với một số hương vị của sed; cờ "-i" của sed yêu cầu một phần mở rộng được cung cấp. (ví dụ. sed -i.backup '/pattern to match/d' ./infile) Điều đó khiến tôi vượt qua các chỉnh sửa tại chỗ. - avelis
@SiegeX Tốt hơn, đừng áp dụng các lệnh như sed cho bất kỳ tệp nào không được kiểm soát phiên bản. - MatrixFrog
Một lưu ý khác cho người dùng Mac OS X: vì một số lý do, cờ -i yêu cầu đối số được chuyển, ngay cả khi nó chỉ là một chuỗi rỗng, như sed -i '' '/pattern/d' ./infile. - geerlingguy


có nhiều cách khác để xóa các dòng có chuỗi cụ thể bên cạnh sed

lúng túng

awk '!/pattern/' file > temp && mv temp file

Ruby (1.9+)

ruby -i.bak -ne 'print if not /test/' file

Perl

perl -ni.bak -e "print unless /pattern/" file

Shell (bash3.2 +)

while read -r line
do
  [[ ! $line =~ pattern ]] && echo "$line"
done <file > o 
mv o file

GNU grep

grep -v "pattern" file > temp && mv temp file

và dĩ nhiên sed (in nghịch đảo nhanh hơn xóa thực tế.)

sed -n '/pattern/!p' file 

525
2018-03-23 23:57



1 cho đầy đủ! - Adri C.S.
làm thế nào để xóa một dòng cụ thể với một mô hình và cũng là dòng ngay trên nó? Tôi có tiền phạt với hàng ngàn dòng như vậy ở giữa các dữ liệu khác nhau. - oortcloud_domicile
Trên OS / X, biến thể shell không bảo vệ các khoảng trống phía trước, nhưng biến thể grep -v làm việc tốt cho tôi. - Paul Beusterien
các sed Ví dụ có một hành vi khác nhau, nó chỉ greps! nó phải là một cái gì đó như sed -n -i '/pattern/!p' file. - caesarsol
Phiên bản grep không hoạt động khi mọi dòng khớp với mẫu. Làm tốt hơn: grep -v "pattern" file > temp; mv temp file Điều này có thể áp dụng cho một số ví dụ khác tùy thuộc vào giá trị trả lại. - Chris Maes


Bạn có thể sử dụng sed để thay thế các dòng trong một tệp. Tuy nhiên, nó có vẻ chậm hơn nhiều so với sử dụng grep cho nghịch đảo thành tệp thứ hai và sau đó di chuyển tệp thứ hai trên tệp gốc.

ví dụ.

sed -i '/pattern/d' filename      

hoặc là

grep -v "pattern" filename > filename2; mv filename2 filename

Lệnh đầu tiên mất 3 lần lâu hơn trên máy của tôi anyway.


188
2017-11-02 02:37



Bỏ phiếu cho câu trả lời của bạn quá, chỉ vì bạn đã thử so sánh hiệu suất! - anuragw
1 để cung cấp tùy chọn ghi đè tệp hiện tại bằng dòng grep. - Rhyuk
Giải pháp 'grep' thứ hai cũng tốt hơn cho các tệp lớn - simoes
Tôi tò mò về sự khác biệt hiệu suất sẽ là gì nếu sed '/pattern/d' filename > filename2; mv filename2 filename - Pete
(sử dụng ubuntu's / usr / share / dict / words) grep và mv: 0.010s | sed tại chỗ: 0.197s | sed và mv: 0,031 giây - ReactiveRaven


Cách dễ dàng để làm điều đó, với GNU sed:

sed --in-place '/some string here/d' yourfile

51
2018-01-02 17:56



Một mẹo thuận tiện cho những người khác vấp phải chuỗi Q & A này và mới dùng shell scripting: Các tùy chọn ngắn là tốt cho việc sử dụng một lần trên dòng lệnh, nhưng các tùy chọn dài nên được ưa thích hơn trong kịch bản vì chúng dễ đọc hơn. - Dennis
1 cho cờ --in-place. Tôi cần phải kiểm tra điều đó trên các tệp được bảo vệ quyền. (phải làm một số người dùng chà.) - Bee Kay
Lưu ý rằng tùy chọn dài chỉ có sẵn trên GNU sed. Người dùng Mac và BSD sẽ cần cài đặt gsed để thực hiện theo cách này. - Matt


Bạn có thể cân nhắc sử dụng ex (một trình soạn thảo dựa trên lệnh chuẩn của UNIX):

ex +g/match/d -cwq file

Ở đâu:

  • + thực thi lệnh Ex (man ex), giống như -c thực hiện wq (viết và bỏ)
  • g/match/d - Ex lệnh để xóa các dòng với match, xem: Sức mạnh của g

Ví dụ trên là phương pháp tuân thủ POSIX để chỉnh sửa tại chỗ một tệp theo điều này đăng tại Unix.SE và Thông số POSIX cho ex.


Sự khác biệt với sed là:

sed là một Stream EDitor, không phải là một trình soạn thảo tập tin.BashFAQ

trừ khi bạn tận hưởng mã không thể chuyển nhượng, chi phí I / O và một số tác dụng phụ xấu khác. Vì vậy, về cơ bản một số thông số (chẳng hạn như tại chỗ /-i) là các phần mở rộng FreeBSD không chuẩn và có thể không có sẵn trên các hệ điều hành khác.


25
2017-10-17 11:54



điều đó thật tuyệt ... khi tôi làm man ex nó mang lại cho tôi con người vim, dường như ex là một phần của vim ... nếu tôi hiểu đúng nghĩa là cú pháp mẫu cho match Là vimregex.com tương tự nhưng khác với hương vị POSIX và PCRE? - Anentropic
:g  Là Tuân thủ POSIX lệnh với một số sự khác biệt nhỏ. Tôi cho rằng PCRE dựa trên nó. - kenorb


Tôi đã đấu tranh với điều này trên Mac. Thêm vào đó, tôi cần phải làm điều đó bằng cách sử dụng thay thế biến. Vì vậy, tôi đã sử dụng:

sed -i '' "/$pattern/d" $file

Ở đâu $file là tệp cần xóa và $pattern là mẫu phù hợp để xóa. Chọn '' từ đây bình luận. Điều cần lưu ý ở đây là sử dụng dấu ngoặc kép trong "/$pattern/d". Biến sẽ không hoạt động khi chúng tôi sử dụng dấu nháy đơn.


13
2018-03-09 15:39



Mac sed yêu cầu tham số sau -i, vì vậy nếu bạn không muốn sao lưu, bạn vẫn phải thêm một chuỗi rỗng: -i '' - wisbucky


Để có được kết quả giống như grep bạn có thể làm được việc này:

echo "$(grep -v "pattern" filename)" >filename

12
2018-06-13 19:24



Điều này chỉ tốt cho bash vỏ hoặc tương tự (không tcsh). - esmit


Tôi đã tạo một điểm chuẩn nhỏ với một tệp có chứa khoảng 345 000 dòng. Cách với grep có vẻ nhanh hơn 15 lần so với sed trong trường hợp này.

Tôi đã thử cả hai có và không có các thiết lập LC_ALL = C, nó dường như không thay đổi thời gian đáng kể. Chuỗi tìm kiếm (CDGA_00004.pdbqt.gz.tar) nằm ở giữa tệp.

Dưới đây là các lệnh và thời gian:

time sed -i "/CDGA_00004.pdbqt.gz.tar/d" /tmp/input.txt

real    0m0.711s
user    0m0.179s
sys     0m0.530s

time perl -ni -e 'print unless /CDGA_00004.pdbqt.gz.tar/' /tmp/input.txt

real    0m0.105s
user    0m0.088s
sys     0m0.016s

time (grep -v CDGA_00004.pdbqt.gz.tar /tmp/input.txt > /tmp/input.tmp; mv /tmp/input.tmp /tmp/input.txt )

real    0m0.046s
user    0m0.014s
sys     0m0.019s

10
2018-03-19 12:45



nền tảng của bạn là gì? Bạn sử dụng phiên bản sed / perl / grep nào? - hagello
Nền tảng tôi sử dụng là Linux (Gentoo). Phiên bản sed là GNU sed v 4.2.2, phiên bản perl 5 (Tôi không thể biết bản sửa đổi nào tôi đã sử dụng tại thời điểm thử nghiệm), và grep (GNU) là phiên bản 3.0. - Jadzia


SED:

AWK:

GREP:


8
2017-08-25 08:21





Bạn cũng có thể sử dụng nó

 grep -v 'pattern' filename

ở đây -v sẽ in chỉ khác với mẫu của bạn (có nghĩa là Invert match)


7
2018-03-28 07:11