Bir dosyadaki satırların sırasını değiştirme


11

Belirli bir düzende satırların sırasını değiştirmeye çalışıyorum. Çok satırlı bir dosya ile çalışma (ör. 99 satır). Her üç satır için, ikinci satırın üçüncü satır ve üçüncü satırın ikinci satır olmasını isterim.

MİSAL.

1- Giriş:

gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.
...

2- Çıktı:

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.
...

Yanıtlar:


12

Kullanılması awkmatematik tamsayı ve:

awk 'NR%3 == 1 { print } NR%3 == 2 { delay=$0 } NR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay } }' /path/to/input

Modül operatörü tamsayı bölme gerçekleştirir ve kalanını döndürür, böylece her satır için 1, 2, 0, 1, 2, 0 dizisini döndürür [...]. Bunu bilerek, girişi daha sonra kullanmak için modülün 2 olduğu satırlara kaydediyoruz - zekâ, girişi sıfır olduğunda yazdırdıktan hemen sonra.


Burada küçük bir kusur var. Cevabımı gör, küçük iyileştirme bölümü
Sergiy Kolodyazhnyy

İyi yakaladığınız için teşekkürler; Cevabımı şeklinde bir düzeltme ekledim NR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay }.
DopeGhoti

23
$ seq 9 | sed -n 'p;n;h;n;G;p'
1
3
2
4
6
5
7
9
8

Yani, pmevcut çizgiyi çizin , ext'i alın n, heskisini alın, next'i alın, bekletilen Gçizgiyi (desen boşluğuna ekleyin) ve pbu 2-çizgi desen boşluğunu üçüncü ve ikinci çizgilerle değiştirin.


3

Başka bir awk yaklaşımı:

awk '{print $0; if ((getline L2)>0 && (getline L3)>0){ print L3 ORS L2 }}' file

Çıktı:

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

  • (getline L2)>0 && (getline L3)>0- eğer varsa, sonraki 2 kaydı çıkarır

  • her 2. ve 3. kayıt sırasıyla L2ve L3değişkenlere atanır


1
Bu değişkenlerin L harfiyle (küçük harf) başladığını varsayıyorum. Okunabilirlik için kötü seçimlerdir, çünkü on iki ve on üç için rakamlara benziyorlar. Daha iyi bir seçim olabilir line2, vb.
sonraki duyuruya kadar duraklatıldı.

@DennisWilliamson, büyük harf olarak değiştirildi
RomanPerekhrest

1

perlKısa bir komut dosyası kullanma :

user@pc:~$ cat input.txt 
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.

user@pc:~$ perl -ne '$l2=<>; $l3=<>; print $_,$l3,$l2;' input.txt 
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

Komut dosyası tüm dosyayı işler, her satır için (depolanır $_) sonraki iki satırı alır ( $l2ve $l3) ve istenen sırada yazdırır: satır1, satır3, satır2.


1

Bunun bir yolu şöyle olabilir:

sed -e '
   /\n/s/\(.*\)\(\n\)\(.*\)/\3\2\1/;//b
   $!N;$q;N;                            # load up the pattern space with 3 lines provided eof not reached
   P;D;                                 # first just print the first line then interchange the two and print them
' yourfile

Alternatif olarak,

perl -ne 'print $_, reverse scalar <>, scalar <>' yourfile

Sonuçlar

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

1

Neden sadece bir while döngüsü yapmıyorsun? Genişletilmiş biçimde:

( while read a
  do
    read b
    read c
    echo "$a"
    echo "$c"
    echo "$b"
  done
) < input.txt

"Tek satır biçiminde":

( while read a ; do read b ; read c ; echo "$a" ; echo "$c" ; echo "$b" ; done) < input.txt

Çıktılar:

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

1

Perl

perl -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_ . $var if $.%3==0' input.txt

Buradaki fikir , hangisinin ilk önce hangisinin, hangisinin saniyede ve hangisinin 3. satırda olduğunu anlamak için %satır numarası $.değişkenli modulo operatörü kullanmamızdır . Kalan her 3. satır için 0, her 1. ve 2. satır için karşılık gelen sayılar olacaktır.

Ölçek:

$ cat input.txt                                                                                                          
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.

$ perl -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_ . $var if $.%3==0' input.txt                                    
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

Küçük gelişme

İkinci satırı değişkene kaydetme yaklaşımının bir kusuru vardır. Son satır "ikinci" ise, yani kalan satır sayısı için 2 olursa ne olur? Son satırdan çıkarsak, benim ve DopeGhoti'nin cevabındaki orijinal kod yazdırılmaz My dog is orange. Her iki durumda da düzeltme END{}, yazdırma sonrasında geçici değişkenin ayarının kaldırılmasıyla kod bloğunu kullanmaktır . Başka bir deyişle:

$ awk 'NR%3 == 1 { print } NR%3 == 2 { delay=$0 } NR%3 == 0 { print; print delay;delay=""}END{print delay}' input.txt

ve

$ perl -ne '$s=$_ if $.%3==2;print $_ . $s and $s="" if $.%3==0 or $.%3==1;END{print $s}' input.txt 

Bu şekilde, kod bir dosyadaki rasgele sayıda satır için çalışır, sadece 3 ile bölünebilir olanlar için değil.

Yorumlarda bahsedilen sorun için ek düzeltme

Awk durumunda, dosyadaki son satır $ için 1 çıktısı üretirse. % 3, önceki kod yüzünden koşulsuz baskı boş bir yeni satır için çıktı alma sorunu var END{print delay}çünkü, printyorum olarak bahsedilen fonksiyon her zaman üzerinde çalıştığı herhangi bir değişkeni için yeni satırı ekler. perlSürüm durumunda, -nebayraklar printişlevi yeni satırı eklemediği için bu sorun oluşmaz .

Bununla birlikte, awk'ın durumundaki düzeltme, Dope Ghoti tarafından yorumlarda belirtildiği gibi koşullu yapmaktır, geçici değişkenin uzunluğunu doğrulamaktır. Aynı düzeltmenin perl sürümü:

$ perl -ne '$s=$_ if $.%3==2;print $_ . $s and $s="" if $.%3==0 or $.%3==1;END{print $s if length $s}' input.txt 

1
Düzeltmeniz, 'yanlış' satır sayısına sahip dosyalar için boş bir çıktı satırı ekleyeceğinden, kendine özgü küçük bir kusura sahiptir. (For awk) ile cevabımdaki gelişiminizi birleştirmemde bunu düzelttim NR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay }.
DopeGhoti

1
@DopeGhoti Perl'in -nebayraklı baskısı yeni satır çıktısı olmadığından , bu sorun perl ile ortaya çıkmaz . Gerçekten yazdırıyor, ancak boş bir dize, sondaki satır sonu yok. Yine de sorunun cevabını ve aynı düzeltmeyi yanıma ekledim. Teşekkürler !
Sergiy Kolodyazhnyy

1

gayret

Uzun dosyalar için uygun değildir, ancak yalnızca bir dosyayı düzenliyorsanız ve örneğin bazı yaml stanzalarını yeniden sıralamak istiyorsanız hala kullanışlıdır.

İlk önce bir makro kaydedin:

gg qq j ddp j q

Ve sonra istediğiniz kadar tekrarlayın:

@q @q @q ...

Veya sadece örn.

3@q

Açıklama:

  • gg - ilk satıra git
  • qq - makro kaydetmeye başla
  • j - ikinci satıra git
  • ddp - ikinci ve üçüncü satırı değiştir
  • j - dördüncü satıra, yani sonraki üç satırın ilkine git
  • q - kaydı durdur
  • @q - makroyu bir kez oynat
  • 3 @ q - makroyu üç kez tekrar oynat

1
Manuel tekrarlama yerine @q @q @q, bu şekilde yapmak mümkündür 3@q- üç kez tekrarlayın. 100@q- makroyu 100 kez tekrarlayın.
MiniMax

0

Kullanımı: ./shuffle_lines.awk input.txt

Shebang kontrol #!/usr/bin/awk -fçünkü awkkonumu sisteminizde farklı olabilir.

#!/usr/bin/awk -f

{
    if ((NR + 1) % 3 == 0) {
        buffer = $0;
    } else if (NR % 3 == 0) {
        print $0 ORS buffer;
        buffer = "";
    } else {
        print;
    }
}
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.