Polecenie Linux, aby połączyć plik z sobą n razy

31

Wziąłem książkę z pliku tekstowego z projektu Gutenberg (około 0,5 MB), którą chcę połączyć ze sobą nrazy, aby wygenerować duży plik tekstowy, na którym mogę przetestować niektóre algorytmy. Czy istnieje komenda linux, której mogę użyć, aby to osiągnąć? catbrzmi idealnie, ale wydaje się, że nie jest zbyt przyjemny w łączeniu pliku z samym sobą, a ponadto nie odnosi się bezpośrednio do nczęści czasowej pytania.

Bryce Thomas
źródło
2
użyć jakiejś pętli i dołączyć? więc powtórz foo.txt >> bar.txt i zawiń to w coś, co uruchomi polecenie tyle razy?
Journeyman Geek

Odpowiedzi:

35

Dwie części tego, dla mnie - po pierwsze - użycie cat do wypisania pliku tekstowego na standardowe wyjście i użycie append w celu dodania go do innego pliku - np. Foo.txt >> bar.txt doda foo.txt do bar.txt

następnie uruchom go n razy za pomocą

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

zastępując n w tym poleceniu swoim numerem

powinien działać, gdzie n jest twoim numerem

Jeśli używasz csh, istnieje polecenie „powtórz”.

powtarzam powiązane części odpowiedzi są kopiowane stąd i przetestowałem je w systemie Ubuntu 11.04 na domyślnej powłoce bash.

Journeyman Geek
źródło
3
Ciekawostka: to faktycznie działa bez zastępowania „n”, w którym to przypadku wykona ciało raz dla każdego znaku między ASCII „1” a ASCII „n” (czyli 62 razy). Ale {1..12}poprawnie uruchomi ciało 12 razy.
Arnout Engelen
1
Możesz po prostu przekierować cały potok, zamiast dołączać go w każdej iteracji:for i in {1..n};do cat foo.txt; done > bar.txt
Toby Speight
2

Nudzę się, więc oto kilka innych metod łączenia pliku z samym sobą, głównie headza pomocą kuli. Wybacz mi, jeśli się nadmiernie tłumaczę, po prostu lubię mówić: P


Zakładając, Nże liczba samopodatków, które chcesz wykonać, i że Twój plik ma nazwę file.

Zmienne:

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)

Biorąc pod uwagę kopię filewywołanego file2, należy podać total_repeatsliczbę razy file, file2aby była taka sama, jak gdyby filebyła połączona z Nczasami.

Mówi się, że MATH jest tutaj mniej więcej: MATH (sedno)

To jest informatyka z pierwszego semestru, ale minęło trochę czasu, odkąd zrobiłem dowód indukcyjny, więc nie mogę się z tym pogodzić ... (również ta klasa rekurencji jest dość dobrze znana, 2^Loopswięc też ...)


POSIX

Używam kilku rzeczy, które nie są posiksowane, ale nie są one niezbędne. Do moich celów:

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

Och, użyłem tylko tego. No cóż, sekcja jest już tutaj ...


Metody


head ze śledzeniem liczby linii.

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

Bez pliku tymczasowego, bez kota, jeszcze za dużo matematyki, cała radość.


teez MATH

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

Tutaj teejest czytanie ze filelecz wiecznie dołączając do niego, więc będzie zachować czytania pliku na powtórzeniu aż headzatrzymuje ją. I wiemy, kiedy to przerwać z powodu MATH . Dołączanie przesadza, więc użyłem pliku tymczasowego. Możesz również przyciąć nadmiar linii file.


evalwładca ciemności!

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

To po prostu rozszerza się cat file file file ...i ewaluuje. Możesz to zrobić również bez $tmppliku:

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

Drugie head„triki” catpolegające na umieszczeniu pośrednika między operacją a operacją zapisu. Możesz też oszukać catz innym, catale to ma niespójne zachowanie. Spróbuj tego:

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

Zmusza seddo odczytania całego pliku jako linii, przechwytuje go, a następnie wkleja $total_repeatswiele razy.

Nie powiedzie się to oczywiście, jeśli w pliku są znaki o wartości NULL. Wybierz taki, o którym wiesz, że go nie ma.

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
}

To wszystko na razie chłopaki, mam nadzieję, że ta arbitralna odpowiedź nikomu nie przeszkadzała. Testowałem je wszystkie wiele razy, ale jestem tylko dwuletnim użytkownikiem powłoki, więc myślę, że o tym myślę. Teraz spać ...

rm $tmp

phicr
źródło
2

Z pewnością możesz użyć catdo tego:

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

Aby uzyskać $nkopie, możesz użyć yespotoku do 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

Złożenie tego razem daje

yes /tmp/f | head -n $n | xargs cat >/tmp/output
Toby Speight
źródło