Sed? Kullanarak bir metin dosyasından belirli satır numaralarını sil?


235

Bir dosyadan bir veya daha fazla belirli satır numarasını silmek istiyorum. Sed kullanarak bunu nasıl yapabilirim?


1
İstediğinize daha spesifik bir örnek verebilir misiniz? Hangi çizgileri kaldıracağınıza nasıl karar vereceksiniz?
Mark Byers

Belki stackoverflow.com/questions/13272717/… adresine bakın ve ters yönde uygulayın (anahtar ilişkilendirilebilir dizide değilse yazdırın).
tripleee

Yanıtlar:


374

5-10 ve 12. satırları silmek istiyorsanız:

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

Bu, sonuçları ekrana yazdırır. Sonuçları aynı dosyaya kaydetmek istiyorsanız:

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

Bu, dosyaya kadar yedekleme yapar file.bakve verilen satırları siler.

Not: Satır numaraları 1'den başlar. Dosyanın ilk satırı 0 değil 1'dir.


32
Tüm unix'lerde "-i" ifadesi bulunmaz. Dosyanızı silen "sed cmd file> file" dosyasına geri düşme hatasını yapmayın.
pra

4
ne 5. satırı son satıra kadar silmek istersem?
Jürgen Paul

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

1
@BrianCampbell Sadece belirli bir satırı silmek için ne yapmalıyım?
Kanagavelu Sugumar

14
@KanagaveluSugumar sed -e '5d' file. Sözdizimi <address><command>; burada <address>, tek bir satır gibi 5veya bir satır aralığı olabilir 5,10ve komut dverilen satırı veya satırları siler. Adresler ayrıca normal ifadeler veya $dosyanın son satırını gösteren dolar işareti olabilir .
Brian Campbell

50

Belirli bir satırı satır numarasıyla silebilirsiniz.

sed -i '33d' file

Bu işlem 33 satır numarasındaki satırı siler ve güncellenen dosyayı kaydeder.


1
Benim durumumda "sed" yanlış bir çizgi kaldırıldı. Bu yüzden bu yaklaşımı kullanır: sed -i '0,/<TARGET>/{/<NEW_VALUE>/d;}' '<SOME_FILE_NAME>'. Teşekkürler!
Eduardo Lucio

Aynı şekilde, bir döngü yazdım ve garip bir şekilde bazı dosyalar doğru satırı kaybetti, ancak bazı dosyalar başka bir satırı da kaybetti, neyin yanlış gittiğine dair hiçbir fikrim yok. (GNU / Linux bash4.2) awk komutu aşağıdaki döngüde iyi çalıştı
FatihSarigol

Bir satır listesinden siliyorsanız sort -r komutunu kullanmaya gerçekten dikkat edin, aksi takdirde ilk
sediniz

Bir döngü içinde yanlış satırların silinmesi hakkındaki yorumlara: en büyük satır numarasıyla başladığınızdan emin olun, aksi takdirde silinen her satır satır numarasını dengeleyecektir…
Skippy le Grand Gourou

25

ve awk de

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

2
Not: Bu garip çizgi benim için sed varyantından (OS-X ve Ubuntu Linux arasında) daha güvenilir bir şekilde çalıştı
Jay Taylor

3
Bunun dosyadaki hiçbir şeyi silmediğini unutmayın. Sadece bu çizgiler olmadan dosyayı stdout'a yazdırır. Bu nedenle, çıktıyı geçici bir dosyaya yönlendirmeniz ve ardından orijinali değiştirmek için geçici dosyayı taşımanız gerekir.
mivk


6

Bu genellikle bir antipattern belirtisidir. Satır numaralarını üreten araç, satırları hemen silen bir takımla değiştirilebilir. Örneğin;

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

( deletelinesihtiyacınız olduğunu düşündüğünüz yardımcı program nerede ) ile aynı

grep -v error logfile

Bu görevi gerçekten yerine getirmeniz gereken bir durumdaysanız sed, satır numaraları dosyasından basit bir komut dosyası oluşturabileceğinizi söyledikten sonra. Mizahi (ama belki biraz karışıklığa) Eğer ile yapabilirsiniz sed.

sed 's%$%d%' linenumbers

Bu, her satıra birer tane olmak üzere satır numaraları dosyasını kabul eder ve standart çıktıda dher birine iliştirilmiş aynı satır numaralarını üretir . Bu, bir seddosyaya veya (bazı platformlarda) başka bir sedörneğe kaydedebileceğimiz geçerli bir komut dosyasıdır :

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

Bazı platformlarda, standart girdi anlamına sed -fgelen seçenek bağımsız değişkenini anlamıyor -, bu nedenle komut dosyasını geçici bir dosyaya yönlendirmeli ve işiniz bittiğinde temizlemelisiniz veya belki de yalnız tire /dev/stdinveya /proc/$pid/fd/1işletim sisteminizle (veya kabuğunuzla) ) vardır.

Her zaman olduğu gibi , sonucu standart çıktıda üretmek yerine hedef dosyayı yerinde düzenleme seçeneğinden -iönce ekleyebilirsiniz . * BSDish platformlarında (OSX dahil) de açık bir argüman sağlamanız gerekir; ortak bir deyim boş bir argüman sağlamaktır; .-fsed-i-i ''


"Antipattern belirtisi" ne katılmıyorum. İşaretleme tabanlı dosya türleri (ör. XML veya JSON) geçerli dosyalar olabilmesi için sonunda belirli satırlar gerektirir. Bu durumda, bu satırları kaldırmak, eklemek istediğiniz şeyi dosyaya koymak ve daha sonra bu satırları yeniden eklemek en makul yaklaşımdır, çünkü satırları hemen arasına koymak çok daha fazla çaba gösterebilir ve olabildiğince sed gibi ekstra araçlardan kaçınma potansiyeli.
Egor Hans

Ne tür bir senaryo hayal ettiğinizi tam olarak anlamıyorum. Bunun meşru bir yaklaşım olduğu senaryolar vardır , ancak gördüğüm vakaların büyük çoğunluğu, ilk örneğimin gösterdiklerini az çok tam olarak yapan yenilerdir. (Belki de gerçekten düşük seviyeli bir dilden gelirler ve problemlerini moleküler seviyenin ötesine bölmek için kullanılırlar, çünkü asm veya C'de
olmalısınız

XML veya JSON'dan satır numarasına göre öğelerin kaldırılması , tehlikeli değilse bile, son derece kırılgan sesler çıkarır .
tripleee

Temel olarak bununla kastettiğim, böyle bir dosyanın yaratıcısı olarak, belgenin sonunda ne olması gerektiğini biliyor olmanız (yani JSON için son birkaç satırda kapanış parantezleri / köşeli parantezler kümesi veya tam olarak XML için kapanış etiketleri). Bunun farkında olarak, böyle bir belgeyi genişletmek için en basit yaklaşım 1) son birkaç satırı kaldırmak, 2) yeni içeriği eklemek, 3) son birkaç satırı yeniden eklemek. Bu şekilde, belge, belgenin ortasına satır eklemenin bir yolunu bulmaya gerek kalmadan, genişletilmeden önce ve sonra geçerli olabilir.
Egor Hans

1
Şimdiye kadar çok sayıda satır (yani bir dosya tarafından sağlanan) için uygun bir çözüme sahip tek cevap budur. Önsöz de mantıklı. Daha fazla oyu hak ediyor. İstersen BTW, baskı onları çizgiler yerine silmek kullanmak pyerine dseçeneğiyle birlikte -n(o olmadan iş olmaz -nve !dya çalışmaz).
Skippy le Grand Gourou

2

Awk ile genelleme yapmak istiyorum.

Dosya sabit boyutlu bloklar tarafından oluşturulduğunda ve silinecek satırlar her blok için tekrarlandığında, awk bu şekilde düzgün çalışabilir

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

Bu örnekte blok için boyut 2000'dir ve [1..713] ve [1026..1029] satırlarını yazdırmak istiyorum.

  • NR awk tarafından geçerli satır numarasını saklamak için kullanılan değişkendir.
  • % iki tamsayının bölünmesinin geri kalanını (veya modülünü) verir;
  • nl=((NR-1)%BLOCKSIZE)+1Burada nl değişkenine mevcut bloğun içindeki satır numarasını yazıyoruz . (aşağıya bakınız)
  • ||ve &&mantıksal operatör olan YA ve VE .
  • print $0 tüm satırı yazar

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
Deliliğe neden olan isminle yaşama şekline hayranım.
Jukka Dahlbom
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.