Gibt es eine Möglichkeit, mehrere Variablen (nicht nur ganze Zahlen) in forSchleifen anzugeben bash? Ich kann 2 Akten haben, die beliebigen Text enthalten, mit dem ich arbeiten müsste.
Was ich funktionell brauche, ist so etwas:
for i in $(cat file1) and j in $(cat file2);do command $i $j;done
Erstens, lesen Sie keine Zeilen mit for , da es einige unvermeidbare Probleme beim Lesen von Zeilen durch Wortteilung gibt.
Wenn Sie Dateien gleicher Länge annehmen oder nur eine Schleife ausführen möchten, bis die kürzere von zwei Dateien gelesen wurde, ist eine einfache Lösung möglich.
while read -r x && read -r y <&3;do...done<file1 3<file2
Es ist schwierig, eine allgemeinere Lösung zusammenzustellen, da die readRückgabe falsch ist und mehrere andere Gründe vorliegen. In diesem Beispiel kann eine beliebige Anzahl von Streams gelesen und nach der kürzesten oder längsten Eingabe zurückgegeben werden.
#!/usr/bin/env bash# Open the given files and assign the resulting FDs to arrName.# openFDs arrname file1 [file2 ...]
openFDs(){local x y i arr=$1[[-v $arr ]]||return1
shiftfor x;do{ exec {y}<"$x";}2>/dev/null ||return1
printf -v "${arr}[i++]"%d "$y"done}# closeFDs FD1 [FD2 ...]
closeFDs(){local xfor x;do
exec {x}<&-done}# Read one line from each of the given FDs and assign the output to arrName.# If the first argument is -l, returns false only when all FDs reach EOF.# readN [ -l ] arrName FD1 [FD2 ...]
readN(){if[[ $1 ==-l ]];thenlocal longest
shiftelselocal longest=filocal i x y status arr=$1[[-v $arr ]]||return1
shiftfor x;doif IFS= read -ru "$x""${arr}[i]"||{ unset -v "${arr}[i]";[[ ${longest+_}]]&&return1;};then
status=0fi((i++))donereturn ${status:-1}}# readLines file1 [file2 ...]
readLines(){local-a fds lines
trap 'closeFDs "${fds[@]}"' RETURN
openFDs fds "$@"||return1while readN -l lines "${fds[@]}";do
printf '%-1s '"${lines[@]}"
echodone}{
readLines /dev/fd/{3..6}||{ echo 'error occured'>&2; exit 1;}}<<<$'a\nb\nc\nd'3<&0<<<$'1\n2\n3\n4\n5'4<&0<<<$'x\ny\nz'5<&0<<<$'7\n8\n9\n10\n11\n12'6<&0# vim: set fenc=utf-8 ff=unix ts=4 sts=4 sw=4 ft=sh nowrap et:
Also je nachdem, ob es readNgeht -l, ist die Ausgabe entweder
a 1 x 7
b 2 y 8
c 3 z 9
d 41051112
oder
a 1 x 7
b 2 y 8
c 3 z 9
Das Lesen mehrerer Streams in einer Schleife, ohne alles in mehreren Arrays zu speichern, ist nicht allzu häufig. Wenn Sie nur Arrays lesen möchten, sollten Sie einen Blick darauf werfen mapfile.
||funktioniert bei mir nicht Es verarbeitet Datei1 dann Datei2 , aber es hält die Dateien synchronisiert &&, wodurch die while- Schleife beim ersten Mal beendet wird . - GNU Bash 4.1.5
Peter.O
Ich hatte keinen freien Moment zum Testen - ja, Sie möchten wahrscheinlich beide Elemente pro Iteration. Der ||Operator "Liste" schließt wie in den meisten Sprachen kurz. Sicherlich wurde dies tausend Mal beantwortet, bevor ...
ormaaj
Der Punkt ist nicht die Häufigkeit, mit der etwas zuvor erwähnt wurde. Es ist vielmehr so, dass der Code, den Sie aktuell in Ihrer Antwort anzeigen, nicht funktioniert . Basierend auf Ihrem " wahrscheinlich wollen beide Elemente ..", klingt es, als hätten Sie es noch nicht getestet.
Peter.O
@ Peter.O Mir ist bewusst. Es wurde behoben.
Ormaaj
2
Tun getan; fertig - du brauchst zwei fors und zwei dones:
for i in $(< file1);dofor j in $(< file2);do echo $i $j;done;done
Datei2 wird natürlich für jedes Wort in Datei1 einmal verarbeitet.
Die Verwendung von <anstelle von cat sollte in den meisten Fällen einen unauffälligen Leistungszuwachs bedeuten. Kein Teilprozess involviert. (Unsicher über den letzten Satz).
Unkomprimiert:
for i in $(< file1)dofor j in $(< file2)do
echo $i $j
donedone
Wenn Sie keine Wörter, sondern Zeilen lesen und das Leerzeichen beibehalten möchten, verwenden Sie while und read:
while read line;dowhile read second;do echo "${line}${second}";done<file2 ;done<file1
Wenn Sie 2 Dateien anhängen und nicht verschachteln möchten:
Sie sagen, es ist kein Unterprozess beteiligt. Ist das () nicht eine Unterschale? Ich möchte nicht hängend sein, aber ich bin mir nicht sicher, was jetzt passiert. Zum Beispiel weiß ich, dass wenn ich ein Skript habe und ich nicht möchte, dass es die aktuelle Shell mit CDs verschmutzt, ich es in einem () mache. Läuft auch (sleep 4) & zum Beispiel gefolgt von einem ps zeigt mir, dass der Prozess noch läuft. Können Sie das bitte näher erläutern?
Silverrocker
Tut mir leid, ich spiele hier sehr viel ohne Fundament. Ich dachte, ich hätte es gehört, aber vielleicht ist es nur der <Vergleich zu cat. Und ich bin mir nicht sicher, wie ich es testen soll und wann es semantisch wichtig wird. Wenn Pipes aufgerufen werden, sprudeln Variablen in Unterprozessen nicht in den Hauptprozess, aber wir haben hier keine Variablen. Ich schlage den kritischen Satz durch, bis jemand ihn klären kann.
Benutzer unbekannt
0
whilehat eine interessante Syntax. Sie können mehrere Befehle vor die do ... whileSchleife stellen, und der betreffende Fall muss möglicherweise mit dieser Funktion jonglieren. Dies hängt von Ihren speziellen Anforderungen ab: Lesen Sie bis zum Ende der längsten Datei oder nur bis zum Ende der kürzesten Datei.
Beispielsweise funktioniertread || read einfach nicht (gemäß den Anforderungen der Frage), da beim Lesen der ersten trueDatei das Lesen der zweiten Datei übersprungen wird, bis die erste Datei von Anfang bis Ende gelesen wurde ... Dann wegen des Status wird truedie while-Schleife fortgesetzt und liest die zweite Datei von Anfang bis Ende.
read && readliest Dateien gleichzeitig (synchron), wenn Sie nur bis zur kürzesten Datei lesen möchten. Wenn Sie jedoch beide Dateien lesen möchten, eofmüssen Sie mit den while'sSyntaxanforderungen arbeiten, d. H. durch den Befehl unmittelbar vor der do whileSchleife, der einen Rückkehrcode ungleich Null erzeugt, um aus der while-Schleife auszubrechen.
Hier ist ein Beispiel, wie Sie beide Dateien in eof einlesen können
(Möglicherweise möchten Sie eof3 und eof4 vor dem Lesen testen, aber die allgemeine Idee ist vorhanden, insbesondere im endgültigen Wahr / Falsch-Zustand.
||
funktioniert bei mir nicht Es verarbeitet Datei1 dann Datei2 , aber es hält die Dateien synchronisiert&&
, wodurch die while- Schleife beim ersten Mal beendet wird . - GNU Bash 4.1.5||
Operator "Liste" schließt wie in den meisten Sprachen kurz. Sicherlich wurde dies tausend Mal beantwortet, bevor ...Tun getan; fertig - du brauchst zwei fors und zwei dones:
Datei2 wird natürlich für jedes Wort in Datei1 einmal verarbeitet.
Die Verwendung von <anstelle von cat sollte in den meisten Fällen einen unauffälligen Leistungszuwachs bedeuten.
Kein Teilprozess involviert.(Unsicher über den letzten Satz).Unkomprimiert:
Wenn Sie keine Wörter, sondern Zeilen lesen und das Leerzeichen beibehalten möchten, verwenden Sie while und read:
Wenn Sie 2 Dateien anhängen und nicht verschachteln möchten:
Wenn Sie 2 Dateien komprimieren möchten, verwenden Sie Einfügen:
quelle
<
Vergleich zucat
. Und ich bin mir nicht sicher, wie ich es testen soll und wann es semantisch wichtig wird. Wenn Pipes aufgerufen werden, sprudeln Variablen in Unterprozessen nicht in den Hauptprozess, aber wir haben hier keine Variablen. Ich schlage den kritischen Satz durch, bis jemand ihn klären kann.while
hat eine interessante Syntax. Sie können mehrere Befehle vor diedo ... while
Schleife stellen, und der betreffende Fall muss möglicherweise mit dieser Funktion jonglieren. Dies hängt von Ihren speziellen Anforderungen ab: Lesen Sie bis zum Ende der längsten Datei oder nur bis zum Ende der kürzesten Datei.Beispielsweise funktioniert
read || read
einfach nicht (gemäß den Anforderungen der Frage), da beim Lesen der erstentrue
Datei das Lesen der zweiten Datei übersprungen wird, bis die erste Datei von Anfang bis Ende gelesen wurde ... Dann wegen des Status wirdtrue
die while-Schleife fortgesetzt und liest die zweite Datei von Anfang bis Ende.read && read
liest Dateien gleichzeitig (synchron), wenn Sie nur bis zur kürzesten Datei lesen möchten. Wenn Sie jedoch beide Dateien lesen möchten,eof
müssen Sie mit denwhile's
Syntaxanforderungen arbeiten, d. H. durch den Befehl unmittelbar vor derdo while
Schleife, der einen Rückkehrcode ungleich Null erzeugt, um aus der while-Schleife auszubrechen.Hier ist ein Beispiel, wie Sie beide Dateien in eof einlesen können
(Möglicherweise möchten Sie eof3 und eof4 vor dem Lesen testen, aber die allgemeine Idee ist vorhanden, insbesondere im endgültigen Wahr / Falsch-Zustand.
quelle