Durchlaufen des Inhalts einer Datei in Bash


1388

Wie iteriere ich mit Bash durch jede Zeile einer Textdatei ?

Mit diesem Skript:

echo "Start!"
for p in (peptides.txt)
do
    echo "${p}"
done

Ich bekomme diese Ausgabe auf dem Bildschirm:

Start!
./runPep.sh: line 3: syntax error near unexpected token `('
./runPep.sh: line 3: `for p in (peptides.txt)'

(Später möchte ich etwas Komplizierteres tun, $pals nur auf dem Bildschirm auszugeben.)


Die Umgebungsvariable SHELL ist (von env):

SHELL=/bin/bash

/bin/bash --version Ausgabe:

GNU bash, version 3.1.17(1)-release (x86_64-suse-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.

cat /proc/version Ausgabe:

Linux version 2.6.18.2-34-default (geeko@buildhost) (gcc version 4.1.2 20061115 (prerelease) (SUSE Linux)) #1 SMP Mon Nov 27 11:46:27 UTC 2006

Die Datei peptides.txt enthält:

RKEKNVQ
IPKKLLQK
QYFHQLEKMNVK
IPKKLLQK
GDLSTALEVAIDCYEK
QYFHQLEKMNVKIPENIYR
RKEKNVQ
VLAKHGKLQDAIN
ILGFMK
LEDVALQILL

19
Oh, ich sehe, dass hier viele Dinge passiert sind: Alle Kommentare wurden gelöscht und die Frage erneut geöffnet. Nur als Referenz: Die akzeptierte Antwort unter Lesen einer Datei Zeile für Zeile, bei der der Wert einer Variablen zugewiesen wird, behebt das Problem auf kanonische Weise und sollte der akzeptierten hier vorgezogen werden.
Fedorqui 'SO hör auf zu schaden'

Antworten:


2093

Ein Weg, dies zu tun, ist:

while read p; do
  echo "$p"
done <peptides.txt

Wie in den Kommentaren erwähnt, hat dies die Nebenwirkungen, dass führende Leerzeichen gekürzt, Backslash-Sequenzen interpretiert und die letzte Zeile übersprungen werden, wenn ein abschließender Zeilenvorschub fehlt. Wenn dies Bedenken sind, können Sie Folgendes tun:

while IFS="" read -r p || [ -n "$p" ]
do
  printf '%s\n' "$p"
done < peptides.txt

In Ausnahmefällen können Sie die Datei mit einem anderen Dateideskriptor öffnen , wenn der Schleifenkörper aus der Standardeingabe lesen kann:

while read -u 10 p; do
  ...
done 10<peptides.txt

Hier ist 10 nur eine beliebige Zahl (verschieden von 0, 1, 2).


7
Wie soll ich die letzte Zeile interpretieren? Die Datei peptides.txt wird zur Standardeingabe und irgendwie zum gesamten while-Block umgeleitet.
Peter Mortensen

11
"Schlürfen Sie peptides.txt in diese while-Schleife, damit der Befehl 'read' etwas zu verbrauchen hat." Meine "cat" -Methode ist ähnlich und sendet die Ausgabe eines Befehls zur Verwendung durch 'read' ebenfalls in den while-Block. Nur sie startet ein anderes Programm, um die Arbeit zu erledigen.
Warren Young

8
Diese Methode scheint die letzte Zeile einer Datei zu überspringen.
Xastor

5
Doppelte Anführungszeichen !! Echo "$ p" und die Datei .. vertrau mir, es wird dich beißen, wenn du es nicht tust !!! ICH KENNE! lol
Mike Q

5
Beide Versionen können eine letzte Zeile nicht lesen, wenn sie nicht mit einer neuen Zeile abgeschlossen wird. Immer benutzenwhile read p || [[ -n $p ]]; do ...
dawg

447
cat peptides.txt | while read line 
do
   # do something with $line here
done

und die Einzeiler-Variante:

cat peptides.txt | while read line; do something_with_$line_here; done

Diese Optionen überspringen die letzte Zeile der Datei, wenn kein nachfolgender Zeilenvorschub vorhanden ist.

Sie können dies folgendermaßen vermeiden:

cat peptides.txt | while read line || [[ -n $line ]];
do
   # do something with $line here
done

68
Wenn Sie "cat" mit nur einem Argument verwenden, machen Sie im Allgemeinen etwas falsch (oder suboptimal).
JesperE

27
Ja, es ist einfach nicht so effizient wie das von Bruno, weil es unnötigerweise ein anderes Programm startet. Wenn es auf Effizienz ankommt, machen Sie es nach Bruno. Ich erinnere mich an meinen Weg, weil Sie ihn mit anderen Befehlen verwenden können, bei denen die Syntax "Umleiten von" nicht funktioniert.
Warren Young

74
Dies hat ein weiteres, schwerwiegenderes Problem: Da die while-Schleife Teil einer Pipeline ist, wird sie in einer Subshell ausgeführt, und daher gehen alle in der Schleife festgelegten Variablen beim Beenden verloren (siehe bash-hackers.org/wiki/doku). PHP / Mirroring / Bashfaq / 024 ). Dies kann sehr ärgerlich sein (je nachdem, was Sie in der Schleife tun möchten).
Gordon Davisson

25
Ich benutze "cat file |" als Start für viele meiner Befehle, nur weil ich oft Prototypen mit "head file |"
Mat Kelcey

62
Dies ist vielleicht nicht so effizient, aber viel besser lesbar als andere Antworten.
Savage Reader

144

Option 1a: While-Schleife: Jeweils einzelne Zeile: Eingangsumleitung

#!/bin/bash
filename='peptides.txt'
echo Start
while read p; do 
    echo $p
done < $filename

Option 1b: While-Schleife: Jeweils eine Zeile:
Öffnen Sie die Datei und lesen Sie sie aus einem Dateideskriptor (in diesem Fall Dateideskriptor Nr. 4).

#!/bin/bash
filename='peptides.txt'
exec 4<$filename
echo Start
while read -u4 p ; do
    echo $p
done

Für Option 1b: Muss der Dateideskriptor erneut geschlossen werden? ZB könnte die Schleife eine innere Schleife sein.
Peter Mortensen

3
Der Dateideskriptor wird mit den Prozess-Exits bereinigt. Ein explizites Schließen kann durchgeführt werden, um die fd-Nummer wiederzuverwenden. Um einen fd zu schließen, verwenden Sie einen anderen exec mit der & - Syntax wie folgt: exec 4 <& -
Stan Graves

1
Vielen Dank für Option 2. Ich hatte große Probleme mit Option 1, weil ich innerhalb der Schleife von stdin lesen musste. In diesem Fall funktioniert Option 1 nicht.
Masgo

4
Sie sollten deutlicher darauf hinweisen, dass von Option 2 dringend abgeraten wird . @masgo Option 1b soll in diesem Fall arbeiten, und kann mit der Eingabeumleitung Syntax von Option 1a kombiniert wird durch den Austausch done < $filenamemit done 4<$filename(was nützlich ist , wenn Sie die Dateinamen aus einem Befehlsparameter lesen mögen, in diesem Fall kann man einfach ersetzen $filenamedurch $1).
Egor Hans

Ich muss Dateiinhalte tail -n +2 myfile.txt | grep 'somepattern' | cut -f3durchlaufen, z. B. während ich ssh-Befehle innerhalb der Schleife ausführe (verbraucht stdin); Option 2 scheint hier der einzige Weg zu sein?
user5359531

85

Dies ist nicht besser als andere Antworten, aber eine weitere Möglichkeit, die Arbeit in einer Datei ohne Leerzeichen zu erledigen (siehe Kommentare). Ich finde, dass ich oft Einzeiler brauche, um Listen in Textdateien zu durchsuchen, ohne den zusätzlichen Schritt, separate Skriptdateien zu verwenden.

for word in $(cat peptides.txt); do echo $word; done

Mit diesem Format kann ich alles in einer Befehlszeile zusammenfassen. Ändern Sie den Teil "echo $ word" nach Ihren Wünschen und Sie können mehrere durch Semikolons getrennte Befehle ausgeben. Im folgenden Beispiel wird der Inhalt der Datei als Argument für zwei andere Skripte verwendet, die Sie möglicherweise geschrieben haben.

for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done

Wenn Sie dies wie einen Stream-Editor verwenden möchten (learn sed), können Sie die Ausgabe wie folgt in eine andere Datei kopieren.

for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done > outfile.txt

Ich habe diese wie oben beschrieben verwendet, weil ich Textdateien verwendet habe, in denen ich sie mit einem Wort pro Zeile erstellt habe. (Siehe Kommentare) Wenn Sie Leerzeichen haben, in denen Sie Ihre Wörter / Zeilen nicht teilen möchten, wird es etwas hässlicher, aber der gleiche Befehl funktioniert immer noch wie folgt:

OLDIFS=$IFS; IFS=$'\n'; for line in $(cat peptides.txt); do cmd_a.sh $line; cmd_b.py $line; done > outfile.txt; IFS=$OLDIFS

Dadurch wird die Shell lediglich angewiesen, nur in Zeilenumbrüchen und nicht in Leerzeichen zu teilen. Anschließend wird die Umgebung auf den vorherigen Stand zurückgesetzt. An dieser Stelle möchten Sie möglicherweise in Betracht ziehen, alles in ein Shell-Skript einzufügen, anstatt alles in einer einzigen Zeile zusammenzufassen.

Viel Glück!


6
Die Bash $ (<peptides.txt) ist vielleicht eleganter, aber es ist immer noch falsch, was Joao richtig gesagt hat. Sie führen eine Befehlsersetzungslogik durch, bei der Leerzeichen oder Zeilenumbrüche dasselbe sind. Wenn eine Zeile ein Leerzeichen enthält, führt die Schleife für diese eine Zeile ZWEIMAL oder mehr aus. Ihr Code sollte also richtig lauten: für Wort in $ (<peptides.txt); tun .... Wenn Sie sicher wissen, dass es keine Leerzeichen gibt, entspricht eine Zeile einem Wort und Sie sind in Ordnung.
Maxpolk

2
@ JoaoCosta, maxpolk: Gute Punkte, die ich nicht berücksichtigt hatte. Ich habe den ursprünglichen Beitrag bearbeitet, um sie wiederzugeben. Vielen Dank!
Mightypile

2
Durch fordie Verwendung werden die Eingabetoken / Zeilen Shell-Erweiterungen ausgesetzt, was normalerweise unerwünscht ist. Versuchen for l in $(echo '* b c'); do echo "[$l]"; doneSie Folgendes : - Wie Sie sehen werden, wird das *- obwohl ursprünglich ein zitiertes Literal - auf die Dateien im aktuellen Verzeichnis erweitert.
mklement0

2
@dblanchard: Das letzte Beispiel mit $ IFS sollte Leerzeichen ignorieren. Haben Sie diese Version ausprobiert?
mächtiger

4
Die Art und Weise, wie dieser Befehl viel komplexer wird, wenn wichtige Probleme behoben werden, zeigt sehr gut, warum die Verwendung forzum Iterieren von Dateizeilen eine schlechte Idee ist. Plus, der von @ mklement0 erwähnte Erweiterungsaspekt (obwohl dies wahrscheinlich umgangen werden kann, indem maskierte Anführungszeichen eingefügt werden, was die Dinge wiederum komplexer und weniger lesbar macht).
Egor Hans

69

Noch ein paar Dinge, die von anderen Antworten nicht abgedeckt werden:

Lesen aus einer begrenzten Datei

# ':' is the delimiter here, and there are three fields on each line in the file
# IFS set below is restricted to the context of `read`, it doesn't affect any other code
while IFS=: read -r field1 field2 field3; do
  # process the fields
  # if the line has less than three fields, the missing fields will be set to an empty string
  # if the line has more than three fields, `field3` will get all the values, including the third field plus the delimiter(s)
done < input.txt

Lesen aus der Ausgabe eines anderen Befehls mithilfe der Prozessersetzung

while read -r line; do
  # process the line
done < <(command ...)

Dieser Ansatz ist besser, als command ... | while read -r line; do ...weil die while-Schleife hier in der aktuellen Shell ausgeführt wird und nicht wie im Fall der letzteren in einer Subshell. Siehe den entsprechenden Beitrag. Eine in einer while-Schleife geänderte Variable wird nicht gespeichert .

Zum Beispiel das Lesen von einer durch Null getrennten Eingabe find ... -print0

while read -r -d '' line; do
  # logic
  # use a second 'read ... <<< "$line"' if we need to tokenize the line
done < <(find /path/to/dir -print0)

Lesen Sie dazu: BashFAQ / 020 - Wie kann ich Dateinamen finden und sicher behandeln, die Zeilenumbrüche, Leerzeichen oder beides enthalten?

Lesen von mehr als einer Datei gleichzeitig

while read -u 3 -r line1 && read -u 4 -r line2; do
  # process the lines
  # note that the loop will end when we reach EOF on either of the files, because of the `&&`
done 3< input1.txt 4< input2.txt

Basierend auf der Antwort von @ chepner hier :

-uist eine Bash-Erweiterung. Aus Gründen der POSIX-Kompatibilität würde jeder Aufruf ungefähr so ​​aussehen read -r X <&3.

Einlesen einer ganzen Datei in ein Array (Bash-Versionen vor 4)

while read -r line; do
    my_array+=("$line")
done < my_file

Wenn die Datei mit einer unvollständigen Zeile endet (neue Zeile fehlt am Ende), dann:

while read -r line || [[ $line ]]; do
    my_array+=("$line")
done < my_file

Einlesen einer ganzen Datei in ein Array (Bash-Versionen 4x und höher)

readarray -t my_array < my_file

oder

mapfile -t my_array < my_file

Und dann

for line in "${my_array[@]}"; do
  # process the lines
done

Zusammenhängende Posts:


Beachten Sie, dass Sie stattdessen command < input_filename.txtimmer input_generating_command | commandodercommand < <(input_generating_command)
masterxilo

1
Vielen Dank für das Einlesen der Datei in das Array. Genau das, was ich brauche, denn ich brauche jede Zeile, um zweimal zu analysieren, neue Variablen hinzuzufügen, einige Validierungen
durchzuführen

45

Verwenden Sie eine while-Schleife wie folgt:

while IFS= read -r line; do
   echo "$line"
done <file

Anmerkungen:

  1. Wenn Sie das nicht IFSrichtig einstellen, verlieren Sie die Einrückung.

  2. Sie sollten fast immer die Option -r beim Lesen verwenden.

  3. Lies keine Zeilen mit for


2
Warum die -rOption?
David C. Rankin

2
@ DavidC.Rankin Die Option -r verhindert die Interpretation von Backslashs. Note #2ist ein Link, wo es im Detail beschrieben wird ...
Jahid

Kombinieren Sie dies mit der Option "read -u" in einer anderen Antwort und dann ist es perfekt.
Florin Andrei

@FlorinAndrei: Das obige Beispiel benötigt keine -uOption. Sprechen Sie über ein anderes Beispiel mit -u?
Jahid

Sie haben Ihre Links durchgesehen und waren überrascht, dass es keine Antwort gibt, die Ihren Link in Anmerkung 2 einfach verknüpft. Diese Seite bietet alles, was Sie über dieses Thema wissen müssen. Oder werden nur Link-Antworten entmutigt oder so?
Egor Hans

14

Angenommen, Sie haben diese Datei:

$ cat /tmp/test.txt
Line 1
    Line 2 has leading space
Line 3 followed by blank line

Line 5 (follows a blank line) and has trailing space    
Line 6 has no ending CR

Es gibt vier Elemente, die die Bedeutung der von vielen Bash-Lösungen gelesenen Dateiausgabe ändern:

  1. Die leere Zeile 4;
  2. Führende oder nachfolgende Leerzeichen in zwei Zeilen;
  3. Beibehaltung der Bedeutung einzelner Zeilen (dh jede Zeile ist ein Datensatz);
  4. Die Leitung 6 endete nicht mit einem CR.

Wenn Sie die Textdatei zeilenweise einschließlich Leerzeilen und Abschlusszeilen ohne CR verwenden möchten, müssen Sie eine while-Schleife verwenden und einen alternativen Test für die letzte Zeile durchführen.

Hier sind die Methoden, mit denen die Datei geändert werden kann (im Vergleich zu den catzurückgegebenen):

1) Verlieren Sie die letzte Zeile und die führenden und nachfolgenden Leerzeichen:

$ while read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
'Line 1'
'Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space'

(Wenn Sie dies while IFS= read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txtstattdessen tun, behalten Sie die führenden und nachfolgenden Leerzeichen bei, verlieren jedoch die letzte Zeile, wenn sie nicht mit CR abgeschlossen wird.)

2) Wenn Sie die Prozesssubstitution mit catWillen verwenden, wird die gesamte Datei in einem Zug gelesen und die Bedeutung einzelner Zeilen verloren:

$ for p in "$(cat /tmp/test.txt)"; do printf "%s\n" "'$p'"; done
'Line 1
    Line 2 has leading space
Line 3 followed by blank line

Line 5 (follows a blank line) and has trailing space    
Line 6 has no ending CR'

(Wenn Sie das Entfernen "von $(cat /tmp/test.txt)Ihnen lesen Sie die Datei Wort für Wort , anstatt einem Zug. Auch wahrscheinlich nicht , was beabsichtigt ist ...)


Der robusteste und einfachste Weg, eine Datei Zeile für Zeile zu lesen und alle Abstände beizubehalten, ist:

$ while IFS= read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt
'Line 1'
'    Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space    '
'Line 6 has no ending CR'

Wenn Sie führende und handelnde Leerzeichen entfernen möchten, entfernen Sie das IFS=Teil:

$ while read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt
'Line 1'
'Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space'
'Line 6 has no ending CR'

(Eine Textdatei ohne Terminierung \nwird unter POSIX als fehlerhaft angesehen , obwohl sie ziemlich häufig vorkommt. Wenn Sie sich auf das Trailing verlassen können, das \nSie || [[ -n $line ]]in der whileSchleife nicht benötigen .)

Mehr in den BASH FAQ


13

Wenn Sie nicht möchten, dass Ihr Lesevorgang durch Zeilenumbrüche unterbrochen wird, verwenden Sie -

#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
    echo "$line"
done < "$1"

Führen Sie dann das Skript mit dem Dateinamen als Parameter aus.


4
#!/bin/bash
#
# Change the file name from "test" to desired input file 
# (The comments in bash are prefixed with #'s)
for x in $(cat test.txt)
do
    echo $x
done

7
Diese Antwort erfordert die in der Antwort von mayypile genannten Einschränkungen und kann schlimm fehlschlagen, wenn eine Zeile Shell-Metazeichen enthält (aufgrund des nicht zitierten "$ x").
Toby Speight

7
Ich bin tatsächlich überrascht, dass die Leute noch nicht auf das Übliche gekommen sind. Lesen Sie keine Zeilen mit für ...
Egor Hans

3

Hier ist mein Beispiel aus dem wirklichen Leben, wie man Zeilen einer anderen Programmausgabe schleift, nach Teilzeichenfolgen sucht, doppelte Anführungszeichen aus der Variablen löscht und diese Variable außerhalb der Schleife verwendet. Ich denke, ziemlich viele stellen diese Fragen früher oder später.

##Parse FPS from first video stream, drop quotes from fps variable
## streams.stream.0.codec_type="video"
## streams.stream.0.r_frame_rate="24000/1001"
## streams.stream.0.avg_frame_rate="24000/1001"
FPS=unknown
while read -r line; do
  if [[ $FPS == "unknown" ]] && [[ $line == *".codec_type=\"video\""* ]]; then
    echo ParseFPS $line
    FPS=parse
  fi
  if [[ $FPS == "parse" ]] && [[ $line == *".r_frame_rate="* ]]; then
    echo ParseFPS $line
    FPS=${line##*=}
    FPS="${FPS%\"}"
    FPS="${FPS#\"}"
  fi
done <<< "$(ffprobe -v quiet -print_format flat -show_format -show_streams -i "$input")"
if [ "$FPS" == "unknown" ] || [ "$FPS" == "parse" ]; then 
  echo ParseFPS Unknown frame rate
fi
echo Found $FPS

Deklarieren Sie eine Variable außerhalb der Schleife, setzen Sie den Wert und verwenden Sie sie außerhalb der Schleife. Dies erfordert die Syntax <<< "$ (...)" . Die Anwendung muss im Kontext der aktuellen Konsole ausgeführt werden. Anführungszeichen um den Befehl halten neue Zeilen des Ausgabestreams.

Die Schleifenübereinstimmung für Teilzeichenfolgen lautet dann Name = Wertepaar, teilt den rechten Teil von last = Zeichen, löscht das erste Anführungszeichen, löscht das letzte Anführungszeichen, wir haben einen sauberen Wert, der an anderer Stelle verwendet werden kann.


3
Obwohl die Antwort richtig ist, verstehe ich, wie sie hier unten gelandet ist. Die wesentliche Methode ist die gleiche wie in vielen anderen Antworten vorgeschlagen. Außerdem ertrinkt es in Ihrem FPS-Beispiel vollständig.
Egor Hans

0

Das kommt ziemlich spät, aber mit dem Gedanken, dass es jemandem helfen könnte, füge ich die Antwort hinzu. Auch dies ist möglicherweise nicht der beste Weg. headBefehl kann mit -nArgument verwendet werden, um n Zeilen vom Anfang der Datei tailzu lesen, und Befehl kann ebenfalls verwendet werden, um von unten zu lesen. Um nun die n-te Zeile aus der Datei abzurufen, leiten wir n Zeilen und leiten die Daten weiter, um nur eine Zeile aus den weitergeleiteten Daten zu beenden.

   TOTAL_LINES=`wc -l $USER_FILE | cut -d " " -f1 `
   echo $TOTAL_LINES       # To validate total lines in the file

   for (( i=1 ; i <= $TOTAL_LINES; i++ ))
   do
      LINE=`head -n$i $USER_FILE | tail -n1`
      echo $LINE
   done

1
Tu das nicht. Das Durchlaufen von Zeilennummern und das Abrufen jeder einzelnen Zeile über sedoder head+ tailist unglaublich ineffizient und wirft natürlich die Frage auf, warum Sie hier nicht einfach eine der anderen Lösungen verwenden. Wenn Sie die Zeilennummer kennen müssen, fügen Sie Ihrer while read -rSchleife einen Zähler hinzu oder verwenden Sie nl -ba, um jeder Zeile vor der Schleife ein Zeilennummernpräfix hinzuzufügen.
Tripleee

-1

@Peter: Das könnte für dich klappen-

echo "Start!";for p in $(cat ./pep); do
echo $p
done

Dies würde die Ausgabe zurückgeben.

Start!
RKEKNVQ
IPKKLLQK
QYFHQLEKMNVK
IPKKLLQK
GDLSTALEVAIDCYEK
QYFHQLEKMNVKIPENIYR
RKEKNVQ
VLAKHGKLQDAIN
ILGFMK
LEDVALQILL


3
Diese Antwort besiegt alle Prinzipien, die in den obigen guten Antworten festgelegt sind!
Codeforester

3
Bitte löschen Sie diese Antwort.
Morgengrauen

3
Nun Leute, übertreiben Sie nicht. Die Antwort ist schlecht, aber es scheint zu funktionieren, zumindest für einfache Anwendungsfälle. Solange dies vorgesehen ist, nimmt eine schlechte Antwort nicht das Existenzrecht der Antwort.
Egor Hans

3
@EgorHans, ich bin nicht einverstanden: Der Sinn der Antworten besteht darin, den Menschen das Schreiben von Software beizubringen. Menschen zu lehren, Dinge auf eine Weise zu tun, von der Sie wissen , dass sie schädlich für sie sind, und die Menschen, die ihre Software verwenden (Einführung von Fehlern / unerwarteten Verhaltensweisen / usw.), schaden wissentlich anderen. Eine Antwort, von der bekannt ist, dass sie schädlich ist, hat kein "Existenzrecht" in einer gut kuratierten Lehrressource (und das Kuratieren ist genau das, was wir, die Leute, die abstimmen und melden, hier tun sollen).
Charles Duffy
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.