Gibt es einen Vorteil bei der Angabe von './' in einer for-Schleife mit einem Glob?

10

Ich hatte den Eindruck, dass es sicherer sein könnte, ./*.fastqnach Dateien zu suchen, die mit enden .fastq. Zum Beispiel ./würde verhindern , dass die Datei erfassen .fastq. Dies ist offensichtlich falsch, wie im folgenden Beispiel gezeigt:

TMP_DIR=$(mktemp --directory)
mkdir -p ${TMP_DIR}
(cd ${TMP_DIR}
 touch {a,b,c,}.fastq
 ls -a
 echo ""

 echo "# match all:"
 for f in *.fastq ; do
     echo "${f}"
 done
 echo ""

 echo "# with ./:"
 for f in ./*.fastq ; do
     echo "${f}"
 done
)
rm -rf ${TMP_DIR}
.
..
a.fastq
b.fastq
c.fastq
.fastq

# match all:
a.fastq
b.fastq
c.fastq

# with ./:
./a.fastq
./b.fastq
./c.fastq

Weder *.fastqnoch ./*.fastqmit der Datei übereinstimmen .fastq. Ich frage mich jetzt, ob es Sinn macht, ./*.fastqhier oder ./*allgemein etwas zu verwenden.

Frédéric Mahé
quelle
1
Der übliche Punkt ./*ist, dass sichergestellt wird, dass Namen, die mit beginnen, -nicht als Optionen behandelt werden.
Charles Duffy

Antworten:

15

Das ist zunächst ein überraschendes Platzhalterverhalten, da die Beschreibung für das *Platzhalterzeichen lautet:

Entspricht einer beliebigen Zeichenfolge, einschließlich der Nullzeichenfolge.

... bis Sie feststellen, dass dieser Zeitraum etwas Besonderes ist, wenn es sich um das erste Zeichen eines Dateinamens handelt. Der Einführungstext in 3.5.8 Filename Expansionsagt es:

Wenn ein Muster für die Dateinamenerweiterung verwendet wird, wird das Zeichen '.' am Anfang eines Dateinamens oder unmittelbar nach einem Schrägstrich muss explizit abgeglichen werden, es sei denn, die Shell-Option dotglob ist gesetzt.

Das "Verwendungsmuster" des Präfixierens von Platzhaltern ./ist nützlich, um Namen mit führendem Bindestrich in der Bash-Shell zu behandeln , wie steeldriver kommentierte. Dies hat keine Auswirkungen auf die Erweiterung des Platzhalters / Dateinamens, macht es jedoch sicherer / einfacher, mit den Dateinamen umzugehen, wenn Sie auf sie verweisen, wenn sie mit Zeichen beginnen, die diese Programme möglicherweise als Optionen falsch interpretieren. Beispielsweise:

# I want a file named `-n`
$ touch -n
touch: invalid option -- 'n'
Try 'touch --help' for more information.
$ touch -- -n
### ok
$ touch ./-n
### ok

... und jetzt, wo ich habe eine Datei mit dem Namen -n, wenn ich eine Schleife über es mit einem Platzhalter passieren:

for file in *n
do
  echo "$file"
done

... ich bekomme keine Ausgabe!

Aber wenn ich dem Platzhalter ein Präfix voranstelle ./,

for file in ./*n
do
  echo "$file"
done
./-n

... Ich sehe den Dateinamen.

Dies ist ein einfaches Beispiel für Demonstrationszwecke. siehe auch Warum ist printf besser als echo? aus diesem Grund und anderen. Andere Dienstprogramme werden durch andere Optionen ausgelöst, daher ist es besser, die Dateinamen den Dienstprogrammen so sicher wie möglich zu präsentieren. Wenn Sie dem Platzhalter kein "Escape" -Dateinamen voranstellen, müssen Sie Ihre Dienstprogramme auf andere Weise "schützen". Eine übliche Möglichkeit besteht darin, das Ende von Optionen zu signalisieren --, zum Beispiel mit:

for file in *n
do
  mv -- "$file" backup/"$file"
done

... die den -nDateinamen sicher weitergeben mv(wie unter set -x)):

mv -- -n backup/-n
Jeff Schaller
quelle