Bagaimana cara menghapus dari file teks, semua baris yang berisi string tertentu?

1789

Bagaimana saya menggunakan sed untuk menghapus semua baris dalam file teks yang berisi string tertentu?

A Clockwork Orange
sumber

Jawaban:

2760

Untuk menghapus garis dan mencetak output ke standar:

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

Untuk secara langsung memodifikasi file - tidak berfungsi dengan BSD sed:

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

Sama, tetapi untuk BSD sed (Mac OS X dan FreeBSD) - tidak bekerja dengan sed GNU:

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

Untuk secara langsung memodifikasi file (dan membuat cadangan) - berfungsi dengan BSD dan GNU sed:

sed -i.bak '/pattern to match/d' ./infile
SiegeX
sumber
13
Terima kasih, tetapi sepertinya tidak menghapusnya dari file tetapi hanya mencetak isi file teks tanpa string itu.
A Clockwork Orange
115
@ A Clockwork: ya, Anda harus mengarahkan output baik ke file baru dengan sesuatu seperti sed '/pattern to match/d' ./infile > ./newfileatau jika Anda ingin melakukan in-place edit maka Anda dapat menambahkan -iflag ke sed seperti pada sed -i '/pattern to match/d' ./infile. Perhatikan bahwa -ibendera memerlukan sed GNU dan tidak portabel
SiegeX
16
Untuk beberapa rasa sed; Bendera "-i" sed membutuhkan ekstensi untuk disediakan. (eg sed -i.backup '/pattern to match/d' ./infile) Itu membuat saya menyeberang dengan suntingan di tempat.
avelis
9
@ SiegeX Lebih baik lagi, jangan menerapkan perintah seperti sedpada file apa pun yang tidak dikontrol versi.
MatrixFrog
84
Satu lagi catatan untuk pengguna Mac OS X: karena alasan tertentu, flag -i membutuhkan argumen untuk diteruskan, bahkan jika itu hanya string kosong, seperti sed -i '' '/pattern/d' ./infile.
geerlingguy
631

Ada banyak cara lain untuk menghapus baris dengan string spesifik selain 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 (kurang lebih 3,2 dan lebih baru)

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

Dan tentu saja sed(mencetak kebalikannya lebih cepat daripada penghapusan sebenarnya):

sed -n '/pattern/!p' file
kurumi
sumber
4
cara menghapus garis tertentu dengan pola dan juga garis tepat di atasnya? Saya memiliki denda dengan ribuan garis seperti di antara data yang berbeda.
oortcloud_domicile
1
Pada OS / X, variasi shell tidak mempertahankan spasi terdepan, tetapi variasi grep -v bekerja dengan baik untuk saya.
Paul Beusterien
13
yang sedmisalnya memiliki perilaku yang berbeda, hanya greps! harus seperti itu sed -n -i '/pattern/!p' file.
caesarsol
8
Versi grep tidak berfungsi ketika setiap baris cocok dengan polanya. Lebih baik dilakukan: grep -v "pattern" file > temp; mv temp fileIni mungkin berlaku untuk beberapa contoh lain tergantung pada nilai kembali.
Chris Maes
1
"Mencetak kebalikannya lebih cepat daripada penghapusan sebenarnya" - Tidak pada mesin saya (2012 MacBook Air, OS X 10.13.2). Membuat file: seq -f %f 10000000 >foo.txt. sed d: time sed -i '' '/6543210/d' foo.txt0m9.294s asli. sed! p: time sed -i '' -n '/6543210/!p' foo.txt0m13.671s asli. (Untuk file yang lebih kecil, perbedaannya lebih besar.)
jcsahnwaldt mengatakan GoFundMonica
252

Anda dapat menggunakan sed untuk mengganti baris yang ada di file. Namun, tampaknya jauh lebih lambat daripada menggunakan grep untuk kebalikannya menjadi file kedua dan kemudian memindahkan file kedua di atas yang asli.

misalnya

sed -i '/pattern/d' filename      

atau

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

Perintah pertama memakan waktu 3 kali lebih lama pada mesin saya.

slashdottir
sumber
19
Voting jawaban Anda juga, hanya karena Anda mencoba perbandingan kinerja!
anuragw
4
+1 untuk opsi penawaran untuk menimpa file saat ini dengan garis grep.
Rhyuk
2
Solusi 'grep' kedua juga lebih baik untuk file besar
simoes
3
Saya ingin tahu apa perbedaan kinerja jikased '/pattern/d' filename > filename2; mv filename2 filename
Pete
9
(menggunakan / usr / share / dict / words ubuntu) grep dan mv: 0.010s | sed di tempat: 0.197s | sed dan mv: 0,031s
ReactiveRaven
77

Cara mudah untuk melakukannya, dengan GNU sed:

sed --in-place '/some string here/d' yourfile
Kevin Nguyen
sumber
56
Kiat praktis untuk orang lain yang tersandung pada utas T&J ini dan baru mengenal shell scripting: Opsi pendek baik untuk penggunaan satu kali pada baris perintah, tetapi opsi panjang harus lebih disukai dalam skrip karena mereka lebih mudah dibaca.
Dennis
3
+1 untuk bendera --in-place. Saya perlu mengujinya pada izin file yang dilindungi. (harus melakukan penggosokan pengguna.)
Bee Kay
8
Perhatikan bahwa opsi panjang hanya tersedia di sed GNU. Pengguna Mac dan BSD perlu menginstal gsed untuk melakukannya dengan cara ini.
Matt
Kiat lain: jika regex Anda tampaknya tidak cocok, coba -ropsi (atau -E, tergantung versi Anda). Hal ini memungkinkan penggunaan metakarakter regex +, ?, {...}dan (...).
rjh
Ini adalah jawaban yang benar ketika disk Anda tidak memiliki lebih banyak ruang dan Anda tidak dapat menyalin teks ke file lain. Perintah ini melakukan apa yang dipertanyakan?
ferreirabraga
38

Anda dapat mempertimbangkan untuk menggunakan ex(yang merupakan editor berbasis perintah Unix standar):

ex +g/match/d -cwq file

dimana:

  • +mengeksekusi diberi perintah Ex ( man ex), sama seperti -cyang mengeksekusi wq(menulis dan berhenti)
  • g/match/d- Perintah Ex untuk menghapus baris dengan yang diberikan match, lihat: Kekuatan g

Contoh di atas adalah metode yang sesuai dengan POSIX untuk mengedit file di tempat sesuai pos ini di Unix.SE dan spesifikasi POSIX untukex .


Perbedaannya sedadalah:

sedadalah S tream ED itor, bukan file editor. BashFAQ

Kecuali Anda menikmati kode yang tidak dapat ditonton, overhead I / O dan beberapa efek samping buruk lainnya. Jadi pada dasarnya beberapa parameter (seperti in-place / -i) adalah ekstensi FreeBSD non-standar dan mungkin tidak tersedia pada sistem operasi lain.

kenorb
sumber
5
itu hebat ... ketika saya melakukannya man exmemberi saya laki-laki untuk vim, tampaknya exadalah bagian dari vim ... jika saya mengerti benar itu berarti sintaks pola untuk matchadalah vimregex.com yang mirip tetapi berbeda dengan rasa POSIX dan PCRE?
Anentropic
1
:g adalah perintah yang sesuai dengan POSIX dengan beberapa perbedaan kecil . Saya menganggap PCRE didasarkan pada itu.
kenorb
16

Saya berjuang dengan ini di Mac. Plus, saya harus melakukannya menggunakan penggantian variabel.

Jadi saya menggunakan:

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

dimana $filefile dimana penghapusan dibutuhkan dan$pattern merupakan pola yang cocok untuk dihapus.

Saya memilih ''dari komentar ini .

Hal yang perlu diperhatikan di sini adalah penggunaan tanda kutip ganda di "/$pattern/d". Variabel tidak akan berfungsi ketika kami menggunakan tanda kutip tunggal.

Aniket Sinha
sumber
3
Mac sedmemerlukan parameter setelahnya -i, jadi jika Anda tidak ingin cadangan, Anda masih harus menambahkan string kosong:-i ''
wisbucky
Untuk penggunaan shell sed -i "/$pattern/d" $file. Terima kasih atas jawaban Anda.
ashwaqar
14

Saya telah membuat patokan kecil dengan file yang berisi sekitar 345.000 baris. Cara dengan greptampaknya sekitar 15 kali lebih cepat daripada sedmetode dalam kasus ini.

Saya telah mencoba keduanya dengan dan tanpa pengaturan LC_ALL = C, sepertinya tidak mengubah timing secara signifikan. String pencarian (CDGA_00004.pdbqt.gz.tar) ada di suatu tempat di tengah file.

Berikut adalah perintah dan timingnya:

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
Jadzia
sumber
Di platform mana Anda berada? Versi sed / perl / grep mana yang Anda gunakan?
hagello
Platform yang saya gunakan adalah Linux (Gentoo). Versi sed adalah GNU sed v 4.2.2, versi perl perl 5 (Saya tidak tahu revisi mana yang saya gunakan pada saat tes), dan grep (GNU) adalah versi 3.0.
Jadzia
14

Anda juga dapat menggunakan ini:

 grep -v 'pattern' filename

Di sini -vhanya akan mencetak selain pola Anda (itu berarti kecocokan terbalik).

Bhuvanesh
sumber
Bagaimana saya bisa menghapus baris dalam direktori yang berisi string khusus
namannimmo
13

Untuk mendapatkan inplace seperti hasil dengan grepAnda dapat melakukan ini:

echo "$(grep -v "pattern" filename)" >filename
Jahid
sumber
4
Ini hanya baik untuk bashshell atau sejenisnya (tidak tcsh).
esmit
4
perl -i    -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3

Perintah pertama mengedit file di tempat (-i).

Perintah kedua melakukan hal yang sama tetapi menyimpan salinan atau cadangan file asli dengan menambahkan .bk ke nama file (.bk dapat diubah menjadi apa saja).

Kjetil S.
sumber
2

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

Shizzmo
sumber
2

Untuk berjaga - jaga seandainya seseorang ingin melakukannya untuk kecocokan string yang tepat, Anda dapat menggunakan -wflag dalam grep - w secara keseluruhan. Misalnya, jika Anda ingin menghapus garis yang memiliki angka 11, tetapi pertahankan garis dengan angka 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

Ini juga berfungsi dengan -fbendera jika Anda ingin mengecualikan beberapa pola yang tepat sekaligus. Jika "daftar hitam" adalah file dengan beberapa pola pada setiap baris yang ingin Anda hapus dari "file":

grep -w -v -f blacklist file
FatihSarigol
sumber
Agak menyesatkan. -w, --word-regexp Select only those lines containing matches that form whole words.vs.-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
Andrey Izman
sumber
Anda menimpa file saat masih digunakan.
Davor Cubranic
@DavorCubranic diperbaiki
Andrey Izman
0

untuk menampilkan teks yang dirawat di konsol

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

untuk menyimpan teks yang dirawat ke dalam file

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

untuk menambahkan info teks yang diperlakukan file yang ada

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

untuk memperlakukan teks yang sudah diperlakukan, dalam hal ini hapus lebih banyak baris dari apa yang telah dihapus

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

yang | moreakan menampilkan teks dalam potongan satu halaman pada satu waktu.

nassim
sumber
0

Anda bisa menggunakan yang lama eduntuk mengedit file dengan cara yang mirip dengan jawaban yang digunakan ex. Perbedaan besar dalam hal ini adalah bahwa edmengambil perintah melalui input standar, bukan sebagai argumen baris perintah seperti exbisa. Saat menggunakannya dalam skrip, cara biasa untuk mengakomodasi ini adalah dengan menggunakan printfperintah pipa ke sana:

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

atau dengan heredoc:

ed -s filename <<EOF
g/pattern/d
w
EOF
Shawn
sumber