sed veya awk: bir kalıbı takip eden n satırı sil


106

Sed'deki (veya benzer herhangi bir araç - örneğin awk) kalıpları ve sayısal aralıkları nasıl karıştırırım? Yapmak istediğim şey, bir dosyadaki belirli satırları eşleştirmek ve ilerlemeden önce sonraki n satırı silmek ve bunu bir boru hattının parçası olarak yapmak istiyorum.

Yanıtlar:


189

Ben buna bir bakacağım.

Bir desenden sonra 5 satırı silmek için (desenle birlikte satır dahil):

sed -e '/pattern/,+5d' file.txt

Bir desenden sonra 5 satır silmek için (desen içeren satır hariç):

sed -e '/pattern/{n;N;N;N;N;d}' file.txt

14
Modelin +Nbir GNU uzantısı olduğuna dikkat edin . Desenli çizgiyi içermesini sağlamak için ikinci örneğinizde ilkini bir nile değiştirin N.
sonraki duyuruya kadar duraklatıldı.

2
desen eşleştikten sonra tüm satırlar nasıl silinir? Sed -e '/ <! - # content end -> </div> /, $ d' out.txt kullanıyorum ama şu hata veriyor: sed: -e expression # 1, char 24: sonra ekstra karakterler komut Şimdiden teşekkürler.
N mol

8
Olanlar benzerdir ancak her durumda biraz farklıdır. İlk tarifte, /pattern/,+5"desen" ( /pattern/) içeren bir satırla başlayan ve 5 satır sonra biten ( ) bir aralık tanımlar +5. Son karakter d, bu aralıktaki her satırda çalıştırılacak bir komuttur, yani "sil". İkinci tarifte, bir aralığı eşleştirmek yerine, sadece kalıbı ( /pattern/) içeren satırla eşleşir ve ardından bir dizi komut çalıştırır: {n;N;N;N;N;d}temelde sonraki satırı ( n) yazdırır ve ardından sonraki 4 satırı okur ve son olarak atar ( N;N;N;N;d).
pimlottc

18
Mac / OS X sistemlerinde kapanış sed -e '/pattern/{n;N;N;N;N;d;}' file.txt
ayracından

1
Bütünlüğü için: To belirli bir düzenle aşağıdaki tüm satırlar silmek something yapın: sed -E '/^something$/,$d'nerede -EPOSIX taşınabilirlik genişletilmiş regex olduğunu.
not2qubit

7

GNU uzantıları olmadan (örneğin macOS'ta):

Bir desenden sonra 5 satırı silmek için (desenle birlikte satır dahil)

 sed -e '/pattern/{N;N;N;N;d;}'

-i ''Yerinde düzenlemek için ekleyin .


6

Basit awk çözümler:

Eşleşen satırları bulmak için kullanılacak normal ifadenin kabuk değişkeninde $regexve atlanacak satır sayısında depolandığını varsayın $count.

Eğer uygun hattı gerekir da atlanır ( $count + 1hat atlanır):

... | awk -v regex="$regex" -v count="$count" \
  '$0 ~ regex { skip=count; next } --skip >= 0 { next } 1'

Eğer eşleşen bir satır olmalıdır değil atlanır ( $countçizgiler sonra maçın atlanır):

... | awk -v regex="$regex" -v count="$count" \
  '$0 ~ regex { skip=count; print; next } --skip >= 0 { next } 1'

Açıklama:

  • -v regex="$regex" -v count="$count"awkDeğişkenleri aynı isimli kabuk değişkenlerine göre tanımlar .
  • $0 ~ regex ilgi alanıyla eşleşir
    • { skip=count; next }atlama sayısını başlatır ve bir sonraki satıra geçerek eşleştirme satırını etkin bir şekilde atlar; 2 çözümde, printdaha önce nextolmasını sağlar o olduğunu değil atlanır.
    • --skip >= 0 atlama sayısını azaltır ve eğer (hala)> = 0 ise, eldeki satırın atlanması gerektiği anlamına gelir.
    • { next } etkin bir şekilde geçerli satırı atlayarak sonraki satıra geçer
  • 1için yaygın olarak kullanılan bir kısaltmadır { print }; yani mevcut satır basitçe yazdırılır
    • Bu komuta yalnızca eşleşmeyen ve atlanmayan satırlar ulaşır.
    • Nedeni 1eşdeğerdir { print }yani 1tanım gereği her zaman (blok) ilişkili işlem koşulsuz olarak yürütülür, bu vasıtalar, doğru olarak değerlendirilir bir Boolean model yorumlanır. Yana orada olduğu hiçbir bu durumda ilişkili eylem, awkvarsayılan baskı hattı.

3

Bu sizin için işe yarayabilir:

cat <<! >pattern_number.txt
> 5 3
> 10 1
> 15 5
> !
sed 's|\(\S*\) \(\S*\)|/\1/,+\2{//!d}|' pattern_number.txt |
sed -f - <(seq 21)
1 
2
3
4
5
9
10
12
13
14
15
21

10
Vay canına, bu şifreli.
pimlottc

3
Akıllı (GNU-Sed'e özgü olsa da) bir çözüm, ancak bir açıklama eklemediğiniz sürece çok az kişi bundan faydalanacaktır. pattern_number.txt1. sütunda eşleşecek deseni ve 2. sütunda atlanacak satır sayısını içeren 2 sütunlu bir dosyadır. İlk sedkomut, dosyayı sedkarşılık gelen eşleştirme ve atlamayı gerçekleştiren bir betiğe dönüştürür ; bu betik 2. komuta -fve stdin ( -) aracılığıyla sağlanır sed. 2. sedkomut, çalıştığını göstermek için çıkışından oluşturulmuş örnek bir ad-hoc girdi dosyası üzerinde seq 21çalışır.
mklement0

Ayrıca, solüsyon bir uyarı ile gelir: yöntemi kullanan olmayan ilk satırı (desen eşleştirme bir) de atlama olmayan yan etkisi vardır atlamak için yinelenen aralığında hatları.
mklement0

Bu etkileyici bir sed kullanımıdır.
Travis Rodman

3

Perl kullanma

$ cat delete_5lines.txt
1
2
3
4
5 hello
6
7
8
9
10
11 hai
$ perl -ne ' BEGIN{$y=1} $y=$.  if /hello/ ; print if $y==1 or $.-$y > 5 ' delete_5lines.txt
1
2
3
4
11 hai
$

2

Bu çözüm, parametre olarak "n" yi iletmenize izin verir ve kalıplarınızı bir dosyadan okuyacaktır:

awk -v n=5 '
    NR == FNR {pattern[$0]; next}
    {
        for (patt in pattern) {
            if ($0 ~ patt) {
                print # remove if you want to exclude a matched line
                for (i=0; i<n; i++) getline
                next
            }
        }
        print
    }
' file.with.patterns -

"-" adlı dosya, awk için stdin anlamına gelir, bu nedenle bu, ardışık düzeniniz için uygundur


2
awk benim sandığımdan çok daha fazla perl benzeri olma yeteneğine sahip!
Martin DeMello
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.