Dosyayı satırlara göre nasıl kısaltabilirim?


13

Bazıları çok uzun olan çok sayıda dosyam var. Dosya sonunu kaldırarak daha büyükse onları belirli bir boyuta kısaltmak istiyorum. Ama sadece bütün çizgileri kaldırmak istiyorum. Bunu nasıl yapabilirim? Linux araç zinciri tarafından ele alınacak bir şey gibi geliyor ama doğru komutu bilmiyorum.

Örneğin, 300 baytlık satırlarla 120.000 baytlık bir dosyam olduğunu ve bunu 10.000 bayt olarak kesmeye çalıştığımı varsayalım. İlk 33 satır kalmalı (9900 bayt) ve geri kalan kısım kesilmelidir. Tam olarak 10.000 bayta kesmek istemiyorum, çünkü bu kısmi bir çizgi bırakacaktı.

Tabii ki dosyalar farklı uzunluklarda ve çizgiler aynı uzunlukta değil.

İdeal olarak, sonuçta elde edilen dosyalar biraz daha uzun değil (kesme noktası uzun bir çizgi üzerindeyse) biraz daha kısa yapılır, ancak bu çok önemli değildir, bu daha kolay olursa biraz daha uzun olabilir. Değişikliklerin doğrudan dosyalara yapılmasını istiyorum (muhtemelen, başka bir yerde kopyalanan yeni dosya, orijinal silinmiş ve yeni dosya taşındı, ancak kullanıcının POV'sinden aynı). Verileri bir sürü yere yönlendiren ve daha sonra geri dönen bir çözüm, dosyayı bozma olasılığını davet ediyor ve bundan kaçınmak istiyorum ...


Cevabımı sildim… Sanırım Bytes'deki dosya boyutu çok açık değildi, üzgünüm. Belki sorunuzu düzenleyebilir ve o kısmı açıklığa kavuşturabilirsiniz (örneğin bir örnekle)?
slhck

@slhck: Sadece belirsiz olduğum için temsilcisi kaybettiğini gördüğüm için üzgünüm ... bunu düzeltebilir miyim bakayım.
Charles

Endişeye gerek yok, ben sadece
sormalıydım

Yanıtlar:


1

sed/ wcEğer karmaşıklık önceki cevapları önlenebilir awkkullanılır. OP tarafından sağlanan örneği kullanarak ( 10000 bayt öncesi tüm satırları gösterir ):

awk '{i += (length() + 1); if (i <= 10000) print $ALL}' myfile.txt

Ayrıca, bayt satırın sonunda değilse 10000. bayt içeren tam satırı gösterir:

awk '{i += (length() + 1); print $ALL; if (i >= 10000) exit}' myfile.txt

Yukarıdaki cevap varsayar:

  1. Metin dosyası Unix satır sonlandırıcısına ( \n) aittir . Dos / Windows metin dosyaları (For \r\n), değişim length() + 1içinlength() + 2
  2. Metin dosyası yalnızca tek baytlık karakter içerir. Çok baytlı bir karakter varsa (unicode ortamında olduğu gibi), çevreyi LC_CTYPE=Cbayt düzeyinde yorumu zorlayacak şekilde ayarlayın .

15

sedYaklaşım iyidir, ama tüm hatlar üzerinde döngü değildir. Kaç satır tutmak istediğinizi biliyorsanız (örnek olarak burada 99 kullanıyorum), bunu şu şekilde yapabilirsiniz:

sed -i '100,$ d' myfile.txt

Açıklama: sednormal bir ifade işlemcisidir. Seçenekte -iverilen, doğrudan bir dosya ( "satır içi") işler - yerine sadece okuma ve standart çıktıya sonuçlarını yazma. 100,$"satır 100'den dosyanın sonuna" anlamına gelir - ve bunu d"sil" anlamına gelecek şekilde doğru tahmin ettiğiniz komut izler . Kısacası, komut şu anlama gelir: "100. satırdan dosyanın sonuna kadar tüm dosyaları myfile.txt dosyasından sil". 99 satırı tutmak istediğiniz için silinecek ilk satır 100'dür.

Düzenleme: Öte yandan, örneğin son 100 satır tutmak istediğiniz günlük dosyaları varsa :

[ $(wc -l myfile.txt) -gt 100 ] && sed -i "1,$(($(wc -l myfile.txt|awk '{print $1}') - 100)) d" myfile.txt

Burada neler oluyor:

  • [ $(wc -l myfile.txt) -gt 100 ]: yalnızca dosyada 100'den fazla satır varsa aşağıdakileri yapın
  • $((100 - $(wc -l myfile.txt|awk '{print $1}'))): silinecek satır sayısını hesaplayın (örneğin, saklanacak (son) 100 hariç dosyanın tüm satırları)
  • 1, $((..)) d: ilk satırdan hesaplanan satıra tüm satırları kaldır

DÜZENLEME: soru daha fazla ayrıntı vermek üzere düzenlendiği için, bu ek bilgiyi yanıtıma da ekleyeceğim. Eklenen gerçekler:

  • dosyada belirli bir boyut kalır (10.000 bayt)
  • her satırın bayt cinsinden belirli bir boyutu vardır (örnekte 300 bayt)

Bu verilerden, örnekte 33 satır anlamına gelen "/" olarak kalacak satır sayısını hesaplamak mümkündür. Hesaplama için kabuk terimi: $((size_to_remain / linesize))(en azından Bash kullanan Linux'ta sonuç bir tamsayıdır). Ayarlanan komut şimdi şunu okuyacaktır:

# keep the start of the file (OPs question)
sed -i '34,$ d' myfile.txt
# keep the end of the file (my second example)
[ $(wc -l myfile.txt) -gt 33 ] && sed -i "1,33 d" myfile.txt

Boyutlar önceden bilindiği için, sedkomuta gömülü bir hesaplamaya artık gerek yoktur . Ancak esneklik için, bazı kabuk betiğinin içinde değişkenler kullanılabilir.

Dosya boyutuna dayalı koşullu işlem için aşağıdaki "test" yapısını kullanabilirsiniz:

[ "$(ls -lk $file | awk ' {print $5}')" -gt 100 ] &&

yani: "boyutu $file100kB'ı aşarsa, yap ..." ( ls -lk5. konumda kB cinsinden dosya boyutunu listeler, dolayısıyla awktam olarak bunu ayıklamak için kullanılır).


OP dosyayı sadece satır cinsinden değil, belirli bir bayt boyutuna göre kesmek istiyor. İlgili cevabımı sildim head -n.
slhck

@slhck Bildirim için teşekkür ederim. Evet, OP niyeti daha net hale getirmek için sorusunu düzenledi. Her satırın kaç bayt olduğunu hesaplamak için araçlara sahip olduğu için, cevabım prensip olarak geçerli kalıyor - kalan satır sayısını hesaplayabiliyor ve sonra dosyaları işlemek için yaklaşımımı kullanıyor. Belki de cevabım içinde kısa bir açıklama yapıyorum
Izzy

Hayır - boyutlar önceden bilinmemektedir. Bu bir örnekti. Her dosya farklı bir boyuta sahip olacak ve satırlar düzensiz uzunluktadır. Bazı dosyaların kesilmesi gerekmez.
Charles

Oh, yine ... Şey, bazı şeyleri net bir şekilde açıklamak zor (çok fazla faset). Kesilmesi gerekmeyen dosyalara gelince, bu muhtemelen dosya boyutuna bağlıdır? Bu kapsanabilir. Ancak bilinen ortalama bir çizgi boyutu bile yoksa, bu bölüm zorlaşır - şu anda (çok fazla ek yük olmadan) kolay bir çözüm düşünemiyorum.
Izzy

Şu anda gelebileceğim tek şey, örneğin ilk n çizgisini almak, bunlara dayalı ortalama bir uzunluk hesaplamak ve bu değeri kullanmaktır. Bu size yardımcı olur mu?
Izzy

0

Bunu yapmak için bir komut bulamadı, ben hızlı bir komut dosyası (test değil) yazdı:

#!/bin/sh

# Usage: $0 glob.* 25000
# where glob.* is a wildcard pattern and 25000 is the maximum number of bytes.

limit=20000
tmp=/tmp/trim
[[ "$2" == +([0-9]) ]] || limit=$2
limit=`expr $len + 1`
for file in $1;
do
    [[ `wc -c $file` -lt $limit ]] && continue
    head -c $file > $tmp
    sed '$d' $tmp
    $tmp > $file
done

-1

Bir dosyadan satır kaldırmak için linux sed komutunu kullanabilirsiniz. Aşağıdaki komut dosyaadı.txt dosyasının son satırını siler:

sed '$d' filename.txt

Awk veya find ile sed komutunuzla eşleşen deseni arayabilirsiniz. Önce awk ile arama yapar veya kısaltmak istediğiniz dosyaları bulursunuz ve sonra sed ile satırları kaldırabilirsiniz.


-1

Kuyruğa benzer bir şey yaptım. Bu durumda yalnızca son 10.000 satırı tutmak için:

TMP=$(tail -n 10000 /path/to/some/file 2>/dev/null) && echo "${TMP}" > /path/to/some/file
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.