Ich habe zwei Textdateien: string.txt und lengths.txt
String.txt:
abcdefghijklmnopqrstuvwxyz
lengths.txt
5
4
10
7
Ich möchte die Datei erhalten
>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz
Ich arbeite mit ungefähr 28.000 Einträgen und sie variieren zwischen 200 und 56.000 Zeichen.
Im Moment benutze ich:
start=1
end=0
i=0
while read read_l
do
let i=i+1
let end=end+read_l
echo -e ">Entry_$i" >>outfile.txt
echo "$(cut -c$start-$end String.txt)" >>outfile.txt
let start=start+read_l
echo $i
done <lengths.txt
Aber es ist sehr ineffizient. Irgendwelche besseren Ideen?
linux
shell-script
user3891532
quelle
quelle
str="$(cat string.txt)"; i=0; while read j; do echo "${file:$i:$j}"; i=$((i+j)); done <length.txt
wäre es .. scheint schnell genug, wie nur von Shell gemacht ..{ while read l<&3; do head -c"$l"; echo; done 3<lengths.txt; } <String.txt
.Antworten:
Du kannst tun
Es bedarf einiger Erklärung:
Die Hauptidee ist die Verwendung
{ head ; } <file
und wird aus der unterschätzten Antwort von @mikeserv abgeleitet . In diesem Fall müssen wir jedoch vielehead
s verwenden, daher wird einewhile
Schleife eingeführt und ein wenig an den Dateideskriptoren angepasst, um diehead
Eingabe aus beiden Dateien zu übergeben (DateiString.txt
als zu verarbeitende Hauptdatei und Zeilenlength.txt
als Argument zur-c
Option). . Die Idee ist, dass der Geschwindigkeitsvorteil dadurch entstehen sollte, dass nichtString.txt
jedes Mal, wenn ein Befehl gefällthead
odercut
aufgerufen wird, nach ihm gesucht werden muss. Dasecho
ist nur, um nach jeder Iteration eine neue Zeile zu drucken.Wie viel es schneller ist (falls vorhanden) und das Hinzufügen
>Entry_i
zwischen Zeilen bleibt als Übung übrig.quelle
read -u 3
zum Lesen aus Deskriptor 3 verwendet werden.bash
. Die große Mehrheit der Linux-basierten Systeme ist nichtbash
installiert (denken Sie an Android und andere eingebettete Systeme).bash
Da es sich um die langsamste Shell von allen handelt, wird das Umschalten auf Bash die Leistung wahrscheinlich stärker beeinträchtigen als der geringe Gewinn, den das Umschalten vonread <&3
auf mitread -u3
sich bringen könnte (was in jedem Fall unbedeutend ist im Vergleich zu den Kosten für die Ausführung eines externen Befehls wiehead
). Ein Wechsel zu ksh93, das bereitshead
integriert ist (und die nicht standardmäßige-c
Option unterstützt), würde die Leistung erheblich verbessern.head -c
(für diehead
Implementierungen, bei denen diese nicht standardmäßige Option verfügbar ist) eine Anzahl von Bytes und keine Zeichen ist. Dies würde bei Multi-Byte-Gebietsschemas einen Unterschied machen.Im Allgemeinen möchten Sie keine Shell-Schleifen zum Verarbeiten von Text verwenden . Hier würde ich verwenden
perl
:Das ist ein Befehl, der liest (mit Pufferung viel effizienter als die der Shell
read
beide Dateien nur einmal liest (ohne dass sie vollständig im Speicher gespeichert sind) Dies wird mehrere Größenordnungen effizienter sein als Lösungen, die externe Befehle in einer Shell-Schleife ausführen.(Fügen Sie die
-C
Option hinzu, wenn diese Zahlen die Anzahl der Zeichen im aktuellen Gebietsschema und nicht die Anzahl der Bytes sein sollen. Bei ASCII-Zeichen wie in Ihrem Beispiel macht dies keinen Unterschied.)quelle
$_
sowohl als Ausgabe- als auch als Eingabeparameterread
, reduziert jedoch die Anzahl der Bytes im Skript.bash
, 16 Sekunden mitPATH=/opt/ast/bin:$PATH ksh93
)).Bash, Version 4
Ausgabe
quelle
Was ist mit
awk
?Erstellen Sie eine Datei
process.awk
mit dem folgenden Code:Speichern Sie es und führen Sie es aus
awk -f process.awk lengths.txt string.txt
quelle
PROCINFO
ist dies jedoch kein Standardawk
, abergawk
. In diesem Fall würde ich eine anderegawk
einzige Funktion bevorzugen , dieFIELDWIDTHS
:awk -vFIELDWIDTHS="$(tr '\n' ' ' < lengths.txt)" '{for(i=1;i<=NF;i++)print">Entry"i ORS$i}' string.txt