Schreiben Sie in einem Bash-Shell-Skript eine for-Schleife, die Zeichenfolgenwerte durchläuft


24

In Bash weiß ich, dass es möglich ist, eine forSchleife zu schreiben , in der eine Regelungsvariable iüber bestimmte Ganzzahlen iteriert. Zum Beispiel kann ich ein Bash-Shell-Skript schreiben, das die ganzen Zahlen zwischen 1 und 10 ausgibt:

#!/bin/bash

for i in {1..10}
do
 echo $i
done

Ist es möglich, stattdessen über eine Schleifensteuerungsvariable zu iterieren, die eine Zeichenfolge ist, wenn ich eine Liste von Zeichenfolgen bereitstelle? Angenommen, ich habe eine Zeichenfolge fname, die einen Dateinamen darstellt. Ich möchte für jeden Dateinamen eine Reihe von Befehlen aufrufen. Zum Beispiel möchte ich den Inhalt fnameeines Befehls wie folgt drucken :

#!/bin/bash

for fname in {"a.txt", "b.txt", "c.txt"}
do
 echo $fname
done

Mit anderen Worten, sollte in der ersten Iteration fnameden Wert haben fname="a.txt", während in der zweiten Iteration fnameden Wert haben sollte fname="b.txt", und so weiter. Leider scheint die obige Syntax nicht ganz korrekt zu sein. Ich möchte die Ausgabe erhalten:

a.txt

b.txt

c.txt

aber wenn ich den obigen Code versuche, erhalte ich diese Ausgabe:

{a.txt,

b.txt,

c.txt}

Können Sie mir bitte helfen, die richtige Syntax zu bestimmen, damit ich den Wert / Inhalt der Variablen iterativ ändern kann fname? Vielen Dank für Ihre Zeit.


5
Entfernen Sie die {}, Sie brauchen nichts, um eine (durch Leerzeichen begrenzte) Liste
Mat

3
@Mat bedeutet, das {} und das ,s zu entfernen . Die Alternative besteht darin, die Leerzeichen zu entfernen. Also entweder "a.txt" "b.txt" "c.txt"oder {"a.txt","b.txt","c.txt"}. Aber ich bevorzuge {a..c}.txtstattdessen.
Manatwork

Antworten:


39

Die korrekte Syntax lautet wie folgt:

#!/bin/bash

for fname in a.txt b.txt c.txt
do
  echo $fname
done

9
Wenn Sie ein Array von Namen annehmen fnames=( a.txt b.txt c.txt ), können Sie auch die Syntax verwenden for f in ${fnames[@]}; do echo $f; done.

1
Ist es wahr, dass for fname in a.txt b.txt c.txtund zu for fname in "a.txt" "b.txt" "c.txt"identischen Ergebnissen führen?
Andrew

Andrew, ja, das stimmt. Sie werden identische Ergebnisse liefern
Ali Gangji

1
Natürlich sollten Sie for f in "${fnames[@]}"; do echo $f; done(mit Anführungszeichen ${fnames[@]}) verwenden, wenn die fnamesWerte Leerzeichen enthalten könnten. Und Sie sollten verwenden "$f", besonders wenn Sie etwas raffinierteres als echo(z . B. catoder cp) tun . (Und selbst wenn Sie nur tun echo, sollten Sie printfstattdessen verwenden.)
Scott

Ich denke @ user13742 sollte auch in der Antwort vermerkt werden.
Fallenreaper

1

Mir scheint, Sie sollten einfach tun ...

printf %s.txt\\n a b c

Ich mag das, obwohl der OP wahrscheinlich etwas anderes vorhatte als Echo, bevor er fertig war.
Elder Geek

0

Wie in den Kommentaren von user13742 vermerkt , können wir Arrays in bashund verwenden ksh:

#!/usr/bin/env bash

files_list=( "a.txt" "b.txt" "c and space.txt" )

for i in "${files_list[@]}"
do
    echo "$i"
    # do something else here,maybe
done

Und funktioniert so:

$ ./iterate_files_array.sh                                                      
a.txt
b.txt
c and space.txt

Einige Shells wie dash( /bin/shunter Ubuntu) unterstützen jedoch keine Arrays. In einem solchen Fall könnten wir auf die Verwendung der hier angegebenen Dokumentenstruktur zurückgreifen:<<

#!/bin/sh

while IFS= read -r line
do
    echo "$line"
done << EOL
one.txt
two.txt
with space.txt
EOL
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.