Linux komutunu n kez kendine birleştirmek için


31

nBazı algoritmaları karşılaştırabileceğim büyük bir metin dosyası oluşturmak için Project Gutenberg'den (yaklaşık 0,5 MB civarında) düz bir metin dosyası alıp kendisiyle birleştirmek istiyorum . Bunu başarmak için kullanabileceğim bir linux komutu var mı? catKulağa ideal geliyor, ancak bir dosyayı kendi üzerine birleştirmekle pek hoş görünmüyor, ayrıca doğrudan nsorunun zaman dilimine de değinmiyor.


2
Bir tür döngü kullanmak ve ekleme? foo.txt >> bar.txt dosyasını tekrarlayın ve komutu birçok kez çalıştıracak bir şeye sarın.
Journeyman Geek

Yanıtlar:


35

Bunun için iki kısım, bana - ilk - metin dosyasını standart çıktıya çıkarmak için cat kullanmak ve başka bir dosyaya eklemek için append kullanmak - örneğin foo.txt >> bar.txt foo.txt'yi bar.txt dosyasına ekleyecektir.

sonra n kere koş

for i in {1..n};do cat foo.txt >> bar.txt; done

bu komuttaki n'yi numaranızla değiştirmek

çalışmalı, n numaranız nerede

Eğer csh kullanıyorsanız, 'tekrarla' komutu vardır.

cevabın ilgili kısımları buradan kopyalanır ve varsayılan bash kabuğundaki bir ubuntu 11.04 sisteminde test edilmiştir.


3
Eğlenceli gerçek: bu aslında 'n' yerine çalışır, bu durumda ASCII '1' ve ASCII 'n' (yani 62 kez) arasındaki her karakter için gövdeyi bir kez çalıştırır. Ancak {1..12}vücudu doğru 12 kez çalıştıracaktır.
Arnout Engelen

1
Her yinelemede eklemek yerine tüm boru hattını yeniden yönlendirmek isteyebilirsiniz:for i in {1..n};do cat foo.txt; done > bar.txt
Toby Speight

2

Sıkıldım, burada bir dosyayı kendi kendine nasıl birleştireceğiniz, çoğunlukla headbir koltuk değneği olarak kullanabileceğiniz birkaç yöntem daha var . Afedersiniz, eğer kendimi fazla açıklarsam, sadece bir şeyler söylemek istiyorum:


Varsayalım Nki kendi birleştirme işlemi yapmak ve dosyanızın isimlendirilmesi file.

Değişkenler:

linecount=$(<file wc -l)

total_repeats=$(echo "2^$N - 1" | bc) # obtained through the power of MATH

total_lines=$((linecount*(total_repeats+1)))

tmp=$(mktemp --suffix .concat.self)

Bir kopyası Verilen filedenilen file2, total_repeatskaç kez fileeklenecek gerekir file2aynı sanki yapmaya filekendisine birleştirilmiş edildi Nkez.

Bahsedilen MATH burada, az ya da çok: MATH (öz)

İlk dönem bilgisayar bilimi olayı oldu ama uzun zamandır bir indüksiyon kanıtı yaptım, bu yüzden üstesinden gelemem ... (ayrıca bu yineleme sınıfının olduğu da oldukça iyi biliniyor. 2^Loops)


POSIX

Posix olmayan birkaç şey kullanıyorum ancak bunlar zorunlu değil. Amaçlarım için:

 yes() { while true; do echo "$1"; done; }

Oh, bunu sadece kullandım. Ah, bölüm zaten burada ...


Yöntemler


head linecount izleme ile.

ln=$linecount
for i in $(seq 1 $N); do
    <file head -n $ln >> file;
    ln=$((ln*2))
done

Temp dosyası yok, kedi yok, henüz matematik bile yok, tüm neşe.


teeile MATH

<file tee -a file | head -n $total_lines > $tmp
cat $tmp > file

İşte ondan teeokuma fileama buna sürekli ekleme, bu yüzden headduruncaya kadar dosyayı tekrar okumaya devam edecek . MATH nedeniyle onu ne zaman durduracağımızı da biliyoruz . Sona doğru düştüğü için geçici bir dosya kullandım. Fazla çizgileri de filekesebilirsin.


eval, karanlığın efendisi!

eval "cat $(yes file | head -n $((total_repeats+1)) | tr '\n' ' ')" > $tmp
cat $tmp > file

Bu sadece genişler cat file file file ...ve ona göre değişir. $tmpDosya olmadan da yapabilirsiniz :

eval "cat $(yes file | head -n $total_repeats | tr '\n' ' ')" |
  head -n $((total_lines-linecount)) >> file

İkinci head"hileler" catarasına ortadaki bir adamı koyarak yazma işlemidir. Bir catbaşkasını catda kandırabilirsin ama bunun tutarsız davranışı var. Bunu dene:

test_double_cat() {
    local Expected=0
    local Got=0
    local R=0
    local file="$(mktemp --suffix .double.cat)"
    for i in $(seq 1 100); do

        printf "" > $file
        echo "1" >> $file
        echo "2" >> $file
        echo "3" >> $file

        Expected=$((3*$(<file wc -l)))

        cat $file $file | cat >> $file

        Got=$(<file wc -l)

        [ "$Expected" = "$Got" ] && R="$((R+1))"
    done
    echo "Got it right $R/100"
    rm $file
}

sed:

<file tr '\n' '\0' |
    sed -e "s/.*/$(yes '\0' | head -n $total_repeats | tr -d '\n')/g" |
        tr '\0' '\n' >> file

Kuvvetler sedbir çizgi olarak dosyanın tamamını okuma içine, hepsi bunun yakalar, o zaman o yapıştırır $total_repeatskaç kez.

Dosyanızda boş karakter varsa, bu elbette başarısız olacaktır. Orada olmadığını bildiğin birini seç.

find_missing_char() {
  local file="${1:-/dev/stdin}"

  firstbyte="$(<$file fold -w1 | od -An -tuC | sort -un | head -n 1)"
  if [ ! "$firstbyte" = "0" ]; then
    echo "\0"
  else
    printf "\\$(printf '%03o\t' $((firstbyte-1)) )"
  fi
}

Hepsi bu kadar beyler, umarım bu keyfi cevap kimseyi rahatsız etmedi. Hepsini defalarca test ettim ama sadece iki yıllık bir kabuk kullanıcısıyım, bu yüzden sanırım bunu aklınızda bulundurun. Şimdi uyu ...

rm $tmp


2

Bunun için kesinlikle kullanabilirsiniz cat:

$ cat /tmp/f
foo
$ cat /tmp/foo /tmp/f
foo
foo

$nKopya almak için , yesiçine pipo kullanabilirsiniz head -n $n:

$ yes /tmp/f | head -n 10
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f

Bunu bir araya getirmek verir

yes /tmp/f | head -n $n | xargs cat >/tmp/output
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.