Làm cách nào để xóa khỏi tệp văn bản, tất cả các dòng có chứa một chuỗi cụ thể?


Câu trả lời:


2759

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

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

Để trực tiếp sửa đổi tệp - không hoạt động với BSD sed:

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

Tương tự, nhưng đối với BSD sed (Mac OS X và FreeBSD) - không hoạt động với GNU sed:

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

Để trực tiếp sửa đổi tệp (và tạo bản sao lưu) - hoạt động với BSD và GNU sed:

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

13
Cảm ơn, nhưng dường như nó không xóa nó khỏi tệp mà chỉ in ra nội dung tệp văn bản mà không có chuỗi đó.
Một chiếc đồng hồ màu cam

115
@A Clockwork: có, bạn cần chuyển hướng đầu ra sang một tệp mới với nội dung tương tự 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 -icờ vào sed như trong sed -i '/pattern to match/d' ./infile. Lưu ý rằng -icờ yêu cầu GNU sed và không thể di động
SiegeX

16
Đố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 đó đã giúp tôi vượt qua các chỉnh sửa tại chỗ.
avelis

9
@SiegeX Tốt hơn hết, đừng áp dụng các lệnh như sedđối với bất kỳ tệp nào không được kiểm soát phiên bản.
MatrixFrog

84
Thêm một lưu ý cho người dùng Mac OS X: vì một số lý do, cờ -i yêu cầu một đối số được thông qua, ngay cả khi đó chỉ là một chuỗi trống, như thế sed -i '' '/pattern/d' ./infile.
ge Muffguy

631

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

AWK

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 (bash 3.2 trở lên)

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à tất nhiên sed(in ngược lại nhanh hơn xóa thực tế):

sed -n '/pattern/!p' file

4
Làm thế nào để xóa một dòng cụ thể với một mẫu và cũng là dòng ngay trên nó? Tôi bị 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

1
Trên OS / X, biến thể shell không bảo toàn khoảng trắng hàng đầu, nhưng biến thể grep -v hoạt động tốt với tôi.
Paul Beusterien

13
các sedví dụ có một hành vi khác nhau, nó chỉ greps! nó phải được cái gì đó như sed -n -i '/pattern/!p' file.
caesarsol

8
Phiên bản grep không hoạt động khi mọi dòng khớp với mẫu. Tốt hơn làm: 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ả về.
Chris Maes

1
"In ngược lại nhanh hơn xóa thực tế" - Không phải trên máy của tôi (MacBook Air 2012, OS X 10.13.2). Tạo tập tin : seq -f %f 10000000 >foo.txt. sed d: time sed -i '' '/6543210/d' foo.txtthực 0m9.294s. sed! p: time sed -i '' -n '/6543210/!p' foo.txtthực 0m13.671s. (Đối với các tệp nhỏ hơn, sự khác biệt là lớn hơn.)
jcsahnwaldt nói GoFundMonica

252

Bạn có thể sử dụng sed để thay thế các dòng tại chỗ trong một tập tin. Tuy nhiên, dường như chậm hơn nhiều so với việc sử dụng grep cho nghịch đảo thành tệp thứ hai và sau đó di chuyển tệp thứ hai so với 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.


19
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

4
+1 để cung cấp tùy chọn ghi đè tệp hiện tại bằng dòng grep.
Rhyuk

2
Giải pháp 'grep' thứ hai cũng tốt hơn cho các tệp lớn
mô phỏng

3
Tôi tò mò về sự khác biệt hiệu suất sẽ là gì nếu đó làsed '/pattern/d' filename > filename2; mv filename2 filename
Pete

9
(sử dụng ubfox's / usr / share / dict / words) grep và mv: 0.010s | sed tại chỗ: 0.197s | sed và mv: 0,031s
ReactiveRaven

77

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

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

56
Một mẹo hữu ích cho những người khác vấp phải chủ đề Hỏi & Đáp này và chưa quen với kịch bản shell: Các tùy chọn ngắn rất 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 ưu tiên trong các tập lệnh vì chúng dễ đọc hơn.
Dennis

3
+1 cho cờ --in-place. Tôi cần phải kiểm tra xem trên các tập tin được bảo vệ quyền. (phải thực hiện một số thao tác xóa người dùng.)
Bee Kay

8
Lưu ý rằng tùy chọn dài chỉ khả dụng 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

Một mẹo khác: nếu regex của bạn dường như không khớp, hãy thử -rtùy chọn (hoặc -E, tùy thuộc vào phiên bản của bạn). Điều này cho phép việc sử dụng các metacharacters regex +, ?, {...}(...).
rjh

Đây là câu trả lời đúng khi đĩa của bạn không còn dung lượng và bạn không thể sao chép văn bản sang tệp khác. Lệnh này làm những gì đã được hỏi?
ferreirabraga

38

Bạn có thể cân nhắc sử dụng ex(là trình soạn thảo dựa trên lệnh Unix tiêu chuẩn):

ex +g/match/d -cwq file

Ở đâu:

  • +thực thi lệnh Ex ( man ex), giống như -cthực thi wq(ghi và thoát)
  • g/match/d- Lệnh Ex để xóa các dòng đã cho match, xem: Sức mạnh của g

Ví dụ trên là một phương pháp tuân thủ POSIX để chỉnh sửa tại chỗ một tệp theo bài đăng này tại các thông số kỹ thuật của exUnix.SEPOSIX cho .


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

sedlà một S tream ED itor, không phải là một trình soạn thảo tập tin. BashFAQ

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


5
đó là tuyệt vời ... khi tôi làm man exnó mang lại cho tôi những người đàn ông cho vim, có vẻ như exlà một phần của vim ... nếu tôi hiểu đúng điều đó có nghĩa cú pháp mẫu cho matchvimregex.com mà là tương tự nhưng khác nhau để POSIX và PCRE hương vị?
Anentropic

1
:g là lệnh tuân thủ POSIX với một số khác biệt nhỏ . Tôi cho rằng PCRE đã dựa trên nó.
kenorb

16

Tôi đã vật lộn 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 $filelà tập tin cần xóa và $patternlà mẫu cần khớp để xóa.

Tôi chọn ''từ nhận xét này .

Đ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 ngoặc đơn.


3
Mac sedyêu cầu một 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 trống:-i ''
wvducky

Để sử dụng vỏ sed -i "/$pattern/d" $file. Cảm ơn bạn vì câu trả lời.
ashwaqar

14

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

Tôi đã thử cả có và không có cài đặt LC_ALL = C, có vẻ như không thay đổi đáng kể thời gian. Chuỗi tìm kiếm (CDGA_00004.pdbqt.gz.tar) nằm ở đâu đó ở 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

nền tảng của bạn là gì? Những phiên bản nào của sed / perl / grep bạn sử dụng?
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 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

14

Bạn cũng có thể sử dụng điều này:

 grep -v 'pattern' filename

Ở đây -vsẽ chỉ in khác với mẫu của bạn (có nghĩa là đảo ngược khớp).


Làm cách nào tôi có thể xóa các dòng trong thư mục chứa một chuỗi cụ thể
namannimmo

13

Để có được kết quả như tại chỗ với grepbạn có thể làm điều này:

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

4
Điều này chỉ tốt cho bashvỏ hoặc tương tự (không tcsh).
nhận


4
perl -i    -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3

Lệnh đầu tiên chỉnh sửa (các) tệp tại chỗ (-i).

Lệnh thứ hai thực hiện tương tự nhưng giữ một bản sao hoặc sao lưu (các) tệp gốc bằng cách thêm .bk vào tên tệp (.bk có thể được thay đổi thành bất kỳ thứ gì).


2

echo -e "/thing_to_delete\ndd\033:x\n" | vim file_to_edit.txt


2

Chỉ trong trường hợp ai đó muốn làm điều đó cho các chuỗi chính xác, bạn có thể sử dụng -wcờ trong grep - w cho toàn bộ. Đó là, ví dụ nếu bạn muốn xóa các dòng có số 11, nhưng giữ các dòng có số 111:

-bash-4.1$ head file
1
11
111

-bash-4.1$ grep -v "11" file
1

-bash-4.1$ grep -w -v "11" file
1
111

Nó cũng hoạt động với -fcờ nếu bạn muốn loại trừ một số mẫu chính xác cùng một lúc. Nếu "danh sách đen" là một tệp có nhiều mẫu trên mỗi dòng mà bạn muốn xóa khỏi "tệp":

grep -w -v -f blacklist file

Một chút sai lệch. -w, --word-regexp Select only those lines containing matches that form whole words.so với-x, --line-regexp Select only those matches that exactly match the whole line. For a regular expression pattern, this is like parenthesizing the pattern and then surrounding it with ^ and $.
Sai

1
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename

Bạn đang ghi đè một tệp trong khi nó vẫn đang được sử dụng.
Davor Cuba

@DavorCubranic đã được sửa
Andrey Izman

0

để hiển thị văn bản được xử lý trong bảng điều khiển

cat filename | sed '/text to remove/d' 

lưu văn bản đã xử lý vào một tập tin

cat filename | sed '/text to remove/d' > newfile

để thêm thông tin văn bản được xử lý một tập tin hiện có

cat filename | sed '/text to remove/d' >> newfile

để xử lý văn bản đã được xử lý, trong trường hợp này, hãy xóa nhiều dòng hơn những gì đã bị xóa

cat filename | sed '/text to remove/d' | sed '/remove this too/d' | more

những | moresẽ hiển thị văn bản trong khối của một trang tại một thời điểm.


0

Bạn có thể sử dụng tốt edđể chỉnh sửa một tệp theo cách tương tự với câu trả lời sử dụng ex. Sự khác biệt lớn trong trường hợp này là ednhận các lệnh của nó thông qua đầu vào tiêu chuẩn, không phải là đối số dòng lệnh như excó thể. Khi sử dụng nó trong một tập lệnh, cách thông thường để thực hiện điều này là sử dụng printfđể ra lệnh cho nó:

printf "%s\n" "g/pattern/d" w | ed -s filename

hoặc với một di sản:

ed -s filename <<EOF
g/pattern/d
w
EOF
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.