Bir dosyanın sadece her nth satırını tutmak nasıl


71

Oldukça büyük bir CSV dosyasına sahibim (75MB). Sadece bir grafik üretmeye çalışıyorum, bu yüzden gerçekten tüm verilere ihtiyacım yok.

Yeniden değerlendirme: n satırını silmek, sonra bir satır tutmak, sonra n satırlarını silmek vb.

Yani dosya şöyle görünüyorsa:

Line 1
Line 2
Line 3
Line 4
Line 5
Line 6

ve n = 2 ise çıkış şöyle olur:

Line 3
Line 6

Bunu yapabiliyor gibi görünüyor sed, ama nasıl yapacağımı çözemedim. Bir bash komutu ideal olabilir, ancak herhangi bir çözüme açığım.


2
Gerçekten 1, 4, 7, vs. yerine 1, 3, 6 vb. Satırları istiyor musunuz?
Ilmari Karonen

2
Bir CSV dosyası olduğundan, ilk satırın meta veri içerdiğini (alan adları gibi) kabul ediyorum. Eğer öyleyse, soru "ilk satırdan sonra her satır" olmalıdır.
iglvzx

7
1, 3, 6 hala bir anlam ifade etmiyor!
wim

1
N = 2, üçgen sayılar için sihirli bir değer olmadığı sürece 1, 3, 5 olmalıdır (1, 3, 6, 10, 15, 21 vs.)
rjmunro

4
İstediğiniz soruyu ("her n. Satır", "n = 2") ve istediğiniz çıktısını (Satır 3, Satır 6) tutarlı hale getirmek için sorunuzu güncelleyebilir misiniz? Gelecekteki okuyucuların kafası karışacak.
Keith Thompson

Yanıtlar:


121
~ $ awk 'NR == 1 || NR % 3 == 0' yourfile
Line 1
Line 3
Line 6

NR(kayıt sayısı) değişkeni satır sayısını kaydeder, çünkü varsayılan davranış RS(kayıt ayırıcı) için yeni satırdır . desen ve eylem awk varsayılan formatta isteğe bağlıdır 'pattern {actions}'. Sadece desen parçasını verdiğimizde, o zaman awktüm koşullarımızı $0model alanlara yazar true.


8
Varsayılanlara teşekkürler, o kadar da ihtiyacın yok:awk 'NR == 1 || NR % 3 == 0'
Kevin

@selman: Kevin'in çözümünü seviyorsanız, cevabınızı güncellemeyi düşünebilirsiniz.
Keith Thompson

4
Neden böyle yaptığını açıklamak ister misin? Bu şekilde eğer biri hafifçe çimdiklemek istiyorsa, umarım açıklamanız onlara yardımcı olacaktır
Ivo Flipse,

Bu yaklaşımın beni 1 ve 2 numaralı hatlara rötuş yaptığını gördüm. awk 'NR == 1 || NR % 2 == 0' myfile.txt | wc -lOrijinal dosyada çift satır varken bu tek bir sayı ile sonuçlanır. kev cevap test vakamda en iyi sonucu veriyor.
Daniel Da Cunha

58

sed Bunu da yapabilirsiniz:

$ sed -n '1p;0~3p' input.txt
Line 1
Line 3
Line 6

man sedolarak açıklar ~:

first ~ step İlk adımdan başlayarak her adımdaki çizgiyi eşleştirin. Örneğin, `` sed -n 1 ~ 2p '' giriş akışındaki tüm tek numaralı satırları yazdırır ve 2 ~ 5 adresi ikinciden başlayarak her beşinci satırda eşleşir. ilk sıfır olabilir; Bu durumda sed, adıma eşitmiş gibi çalışır. (Bu bir uzantıdır.)


6
Bu komutu açıklayabilir misiniz?
qed

1
@ qed Açıklama: 1pilk satırı yazdırır, 0~3p3. satırdan başlayarak her üç satırı yazdırır (bu 1pnedenle satır 1'i yazdırmak için gereklidir). Ancak 0~3bunun standart olmadığını, bir GNU sed uzantısı olduğunu unutmayın .
Arkku,

"Bu bir uzantısıdır." Hangi sürümü kullanıyordunuz?
Victor,

Bu cevap bana Windows PowerShell için çok yardımcı oldu. Öyle genişlettim: sed -n '1p;0~10p' '.\in.txt' > out.txtazaltılmış dosyayı çıktı dosyasına yazdırmak için.
kimliv

22

Perl bunu da yapabilir:

while (<>) {
    print  if $. % 3 == 1;
}

Bu program girişinin ilk satırını ve ardından her üç satırını yazdıracaktır.

Bunu biraz açıklamak için, böyle <>bir whiledöngüde kullanıldığında giriş hatları üzerinde yinelenen satır giriş operatörüdür . Özel değişken $.şu ana kadar okunan satır sayısını içerir ve %modulus operatörüdür.

Bu kod, -nve -eanahtarları kullanarak tek-astar olarak daha kompakt bir şekilde yazılabilir :

perl -ne 'print if $. % 3 == 1'  < input.txt  > output.txt

-eİse anahtarı, bir komut satırı parametresi olarak çalıştırmak için Perl bir kod parçası alır -nanahtar dolaylı olarak kod sarar whileyukarıda gösterildiği gibi döngü.


Düzenleme: Ben ilk istediğini farz olarak aslında ... ziyade hatları 1, 4, 7, 10, daha örnekteki gibi çizgiler 1, 3, 6, 9, ... almak için değiştirmek $. % 3 == 1ile $. == 1 or $. % 3 == 0.


7

Bash komut dosyası ile yapmak istiyorsanız deneyebilirsiniz:

#!/bin/sh

echo Please enter the file name
read fname
echo Please enter the Nth lines that you want to keep
read n

exec<$fname
value=0
while read line
do
    if [ $(( $value % $n )) -eq 0 ] ; then
        echo -e "$line" >> new_file.txt
    fi
        let value=value+1 
done
echo "Check the 'new_file.txt' that has been created in this directory";

Bunu "read_lines.sh" olarak kaydedin ve bash dosyasına + x izinleri vermeyi unutmayın.

chmod +x ./read_lines.sh

1
Bunu sadece standart dışı olarak yayınladıysanız, argümanlardan atlamak için satır sayısını ve dosyayı standart olarak okumak için satır sayısını okuyun, daha basit ve daha faydalı olacaktır. Yaparak hala new_file.txt yapabilirsiniz ./read_lines.sh > new_file.txt.
rjmunro

4

Saf bashta, bir süreci ortaya çıkarmayan bir çözüm:

{ for f in {1..2}; do read line; done;
  while read line; do
    echo $line;
    for f in {1..2}; do read line; done;
  done; } < file

İlk satır dosyanın başında 2 satır atlar whileve sonraki satırı yazdırır ve tekrar 2 satır atlar.

Dosyanız küçükse, bu bir işlem başlatmadığı için işi yapmanın çok etkili bir yoludur. Dosyanız büyük olduğunda, sedio dosyasını kullanmaktan daha verimli olduğu için kullanılmalıdır bash.


1

Bir Python sürümü (her ikisi de Python 2 ve Python 3):

python2 -c "print(''.join(open('file.txt').readlines()[::3]))"

[::3]Daha fazla kontrol için start, end ve step size parametreleri ile değiştirin . Örneğin [10:36:5], 10, 15, ..., 35 numaralı satırları ortaya koyuyor.

Not, readlines()satır sonlarını koruduğundan, orijinal son satır seçilen adım boyutunda belirtilmedikçe, bu çağrının çıktısı boş bir son satırla sona erebilir.

Bir akış sürümü de mümkündür (burada yalnızca bitmiş akıştan sonra verilir):

python -c "import sys;print(''.join(list(sys.stdin)[::3]))" < file.txt
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.