Linux-Befehl, um eine Datei n-mal mit sich selbst zu verknüpfen

31

Ich habe ein einfaches Textdateibuch aus Project Gutenberg (ca. 0,5 MB) genommen, das ich nmal mit sich selbst verknüpfen möchte , um eine große Textdatei zu generieren, mit der ich einige Algorithmen vergleichen kann. Gibt es einen Linux-Befehl, mit dem ich dies erreichen kann? catHört sich ideal an, scheint aber beim Verketten einer Datei mit sich selbst nicht allzu gut zu sein, und geht nicht direkt auf den nzeitlichen Teil der Frage ein.

Bryce Thomas
quelle
2
eine Art Schleife verwenden und anhängen? Also wiederhole foo.txt >> bar.txt und packe das in etwas, das den Befehl so oft ausführt?
Geselle Geek

Antworten:

35

Dazu gibt es zwei Teile: Zunächst muss cat verwendet werden, um die Textdatei in der Standardausgabe auszugeben, und mit append wird sie einer anderen Datei hinzugefügt. Beispiel: foo.txt >> bar.txt foo.txt wird an bar.txt angehängt

dann starte es n mal mit

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

Ersetzen Sie n in diesem Befehl durch Ihre Nummer

sollte funktionieren, wobei n deine nummer ist

Wenn Sie csh verwenden, gibt es den Befehl 'repeat'.

Wiederholungsbezogene Teile der Antwort werden von hier kopiert , und ich habe sie auf einem Ubuntu 11.04-System auf der Standard-Bash-Shell getestet.

Geselle Geek
quelle
3
Unterhaltsame Tatsache: Dies funktioniert tatsächlich, ohne 'n' zu ersetzen. In diesem Fall wird der Text für jedes Zeichen zwischen ASCII '1' und ASCII 'n' einmal ausgeführt (also 62 Mal). Aber {1..12}wird der Körper 12 mal richtig laufen.
Arnout Engelen
1
Möglicherweise möchten Sie nur die gesamte Pipeline umleiten, anstatt sie in jeder Iteration anzufügen:for i in {1..n};do cat foo.txt; done > bar.txt
Toby Speight,
2

Mir ist langweilig, daher hier noch ein paar Methoden, wie man eine Datei mit sich selbst headverknüpft , meistens als Krücke. Verzeihen Sie mir, wenn ich mich selbst übererkläre, ich sage einfach gerne Dinge: P


Angenommen, Ndie Anzahl der Selbstverkettungen, die Sie ausführen möchten, und der Name Ihrer Datei file.

Variablen:

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)

In Anbetracht der eine Kopie filegenannt file2, total_repeatsist die Anzahl der Male filehinzugefügt werden müssten , file2um es die als gleiche zu machen , wenn filewurde mit sich selbst verkettet Nmal.

Said MATH is here, mehr oder weniger: MATH

Es ist erst ein Semester Informatik, aber es ist schon eine Weile her, dass ich einen Induktionsnachweis gemacht habe, damit ich nicht darüber hinwegkomme 2^Loops...


POSIX

Ich benutze ein paar nicht-posix Dinge, aber sie sind nicht wesentlich. Für meine Zwecke:

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

Oh, das habe ich nur benutzt. Na ja, der Abschnitt ist schon da ...


Methoden


head mit Zählerverfolgung.

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

Keine temporäre Datei, keine Katze, noch nicht einmal zu viel Mathe, alle Freude.


teemit MATH

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

Hier teewird von gelesen, fileaber ständig angehängt, sodass die Datei bei Wiederholung so lange gelesen wird, bis sie headangehalten wird. Und wir wissen, wann wir es wegen MATH beenden müssen . Das Anhängen geht über Bord, also habe ich eine temporäre Datei verwendet. Sie könnten auch die überschüssigen Linien fileabschneiden.


eval, der Herr der Dunkelheit!

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

Dies wird einfach erweitert cat file file file ...und ausgewertet. Sie können dies auch ohne die $tmpDatei tun :

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

Der zweite head"Trick" besteht darin cat, einen Zwischenmenschen zwischen den Schreibvorgang zu setzen. Sie könnten auch catmit einem anderen tricksen, cataber das hat ein inkonsistentes Verhalten. Versuche dies:

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

Erzwingt das sedLesen der gesamten Datei als Zeile, erfasst sie vollständig und fügt sie dann $total_repeatsmehrmals ein.

Dies schlägt natürlich fehl, wenn Ihre Datei Nullzeichen enthält. Wählen Sie einen aus, von dem Sie wissen, dass er nicht da ist.

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
}

Das ist alles, Jungs, ich hoffe, diese willkürliche Antwort hat niemanden gestört. Ich habe sie alle oft getestet, aber ich bin nur ein zweijähriger Shell-Benutzer. Denken Sie also daran, denke ich. Jetzt schlafen ...

rm $tmp

phicr
quelle
2

Sie können dafür sicherlich Folgendes verwenden cat:

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

Um $nKopien zu erhalten, können Sie yesFolgendes verwenden 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

Wenn man das zusammensetzt, ergibt sich

yes /tmp/f | head -n $n | xargs cat >/tmp/output
Toby Speight
quelle