Linux-Befehl, um eine Datei n-mal mit sich selbst zu verketten

14061
Bryce Thomas

Ich habe ein Klartext-Dateibuch von Project Gutenberg (ca. 0,5 MB) mitgenommen, das ich mir nmal verketten möchte, um eine große Textdatei zu generieren, auf der ich einige Algorithmen testen kann. Gibt es einen Linux-Befehl, mit dem ich dies erreichen kann? catklingt ideal, scheint aber nicht zu schön zu spielen, wenn man eine Datei an sich selbst ankettet, und spricht nicht direkt den nTeil der Frage an.

28
eine Art Schleife verwenden und anhängen? also foo.txt >> bar.txt wiederholen und das in etwas einpacken, das den Befehl so oft ausführen wird? Journeyman Geek vor 12 Jahren 2

3 Antworten auf die Frage

31
Journeyman Geek

Für mich gibt es zwei Teile: Zuerst mit cat die Textdatei als Standardausgabe ausgeben und mit append in eine andere Datei einfügen - z. B. foo.txt >> bar.txt foo.txt an bar.txt anhängen

dann n mal mit laufen lassen

for i in ;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".

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

Interessante Tatsache: Dies funktioniert tatsächlich ohne Ersetzen von 'n'. In diesem Fall wird der Text für jedes Zeichen zwischen ASCII '1' und ASCII 'n' einmal ausgeführt (also 62-mal). Aber `` führt den Körper 12 Mal korrekt aus. Arnout Engelen vor 8 Jahren 2
Vielleicht möchten Sie nur die gesamte Pipeline umleiten, anstatt sie bei jeder Iteration anzuhängen: `for i in ; do cat foo.txt; done> bar.txt` Toby Speight vor 7 Jahren 1
1
phicr

Mir ist langweilig. Hier sind ein paar weitere Methoden, wie man eine Datei an sich selbst headankettet, meistens mit einer Krücke. Verzeihen Sie mir, wenn ich mich selbst überfordere, ich sage gern Dinge: P


Angenommen, es Nist die Anzahl der Selbstverkettungen, die Sie ausführen möchten und dass Ihre Datei einen Namen hat 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) 

Gegeben eine Kopie von fileangerufenen file2, total_repeatsist die Anzahl, filewie oft hinzugefügt werden müsste file2, um es so zu machen, als wäre filees mit sich selbst verkettet Nworden.

Die besagte MATH ist mehr oder weniger hier: MATH (gist)

Es ist Informatiksachen des ersten Semesters, aber es ist schon eine Weile her, seit ich einen Induktionsbeweis gemacht habe, also kann ich nicht darüber hinwegkommen ... (Auch diese Rekursionsklasse ist ziemlich bekannt, 2^Loopsalso gibt es das auch ...)


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, ich habe nur das benutzt. Na ja, der Abschnitt ist schon da ...


Methoden


head mit Linecount-Tracking.

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 gelesen, fileaber ständig angefügt, so dass die Datei wiederholt gelesen wird, bis sie headangehalten wird. Und wir wissen, wann wir es wegen MATH aufgeben 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 dehnt sich einfach aus cat file file file ...und wertet es aus. Das geht auch ohne die $tmpDatei:

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

Der zweite head"Trick", catindem ein mittlerer Mann zwischen ihm und dem Schreibvorgang platziert wird. Du könntest auch catmit einem anderen catüberlisten, aber das hat 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 die gesamte Datei und fügt sie dann $total_repeatsmehrfach ein.

Dies wird natürlich fehlschlagen, wenn Ihre Datei Nullzeichen enthält. Wähle einen aus, von dem du weißt, dass er nicht da ist.

find_missing_char() { local file="$"  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 für jetzt Jungs, ich hoffe, diese willkürliche Antwort hat niemanden gestört. Ich habe sie alle viele Male getestet, aber ich bin nur zwei Jahre lang Shell-Benutzer. Denken Sie also daran, denke ich. Jetzt schlafen ...

rm $tmp

1
Toby Speight

Sie können dafür sicherlich 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 

Das zusammen zu stellen gibt

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