Bash-Skriptfehler bei Zeichenfolgen mit Pfaden, die Leerzeichen und Platzhalter enthalten


25

Ich habe Probleme, die Grundlagen der Bash-Skripterstellung zu verstehen. Folgendes habe ich bisher:

#!/bin/bash
FILES="/home/john/my directory/*.txt"

for f in "${FILES}"
do
  echo "${f}"
done

Ich möchte nur alle .txtDateien in einer forSchleife auflisten, damit ich sie bearbeiten kann. Aber der Raum in my directoryund der Stern in spielen *.txteinfach nicht gut. Ich habe versucht, es mit und ohne doppelte Anführungszeichen, mit und ohne geschweifte Klammern bei Variablennamen zu verwenden, und kann immer noch nicht alle .txtDateien drucken .

Das ist eine sehr grundlegende Sache, aber ich habe immer noch Probleme, weil ich müde bin und nicht klar denken kann.

Was mache ich falsch?

Ich konnte das obige Skript erfolgreich anwenden, wenn meine DATEIEN kein Leerzeichen oder Sternchen haben ... Ich musste mit oder ohne doppelte Anführungszeichen und geschweifte Klammern experimentieren, damit es funktioniert. Aber in dem Moment, in dem ich sowohl Leerzeichen als auch ein Sternchen habe, wird alles durcheinander gebracht.

Antworten:


33

Innerhalb von Anführungszeichen wird das *nicht zu einer Liste von Dateien erweitert. Um einen solchen Platzhalter erfolgreich zu verwenden, muss er außerhalb von Anführungszeichen stehen.

Selbst wenn der Platzhalter erweitert würde, würde der Ausdruck "${FILES}"zu einer einzelnen Zeichenfolge und nicht zu einer Liste von Dateien führen.

Ein Ansatz, der funktionieren würde, wäre:

#!/bin/bash
DIR="/home/john/my directory/"
for f in "$DIR"/*.txt
do
  echo "${f}"
done

In den obigen Fällen werden Dateinamen mit Leerzeichen oder anderen schwierigen Zeichen korrekt behandelt.

Ein weiter fortgeschrittener Ansatz könnte Bash-Arrays verwenden:

#!/bin/bash
FILES=("/home/john/my directory/"*.txt)
for f in "${FILES[@]}"
do
  echo "${f}"
done

In diesem Fall FILEShandelt es sich um ein Array mit Dateinamen. Die Parens, die die Definition umgeben, machen sie zu einem Array. Beachten Sie, dass das *außerhalb von Anführungszeichen steht. Das Konstrukt "${FILES[@]}"ist ein Sonderfall: Es wird zu einer Liste von Zeichenfolgen erweitert, wobei jede Zeichenfolge einer der Dateinamen ist. Dateinamen mit Leerzeichen oder anderen schwierigen Zeichen werden korrekt behandelt.


1
toll, dass funktioniert
John

Es ist erwähnenswert, dass, wenn Sie Pfade wie diesen durch Funktionen führen, Sie sicherstellen müssen, dass Sie die Variable alleine zitieren, anstatt sie als Teil einer größeren Zeichenfolge zu verketten: for f in "$DIR"/*.txt= fine for f in "$DIR/*.txt"= breaks
pospi

7

Während die Verwendung von Arrays wie von John1024 gezeigt viel sinnvoller ist, können Sie hier auch den Operator split + glob verwenden (wobei eine skalare Variable nicht in Anführungszeichen gesetzt bleibt).

Da Sie nur den Glob-Teil dieses Operators benötigen, müssen Sie den geteilten Teil deaktivieren :

#! /bin/sh -
# that also works in any sh, so you don't even need to have or use bash

file_pattern="/home/john/my directory/*.txt"
# all uppercase variables should be reserved for environment variables

IFS='' # disable splitting

for f in $file_pattern # here we're not quoting the variable so
                       # we're invoking the split+glob operator.
do
  printf '%s\n' "$f" # avoid the non-reliable, non-portable "echo"
done

0

Sie können nur die Platzhalterzeichen außerhalb der Anführungszeichen belassen.
Etwas wie:
für eine in „Dateien mit Leerzeichen“ * „txt“
do
Verarbeitung
getan
Wenn die Platzhalter sich auf Räume erweitern, dann müssen Sie t eine Datei pro Zeile Ansatz verwenden, wie Verwendung ls -l die Liste der erzeugen Dateien und verwenden Sie bash read, um jede Datei abzurufen.


-1

Wenn Sie auf Gruppe von Dateien zu verarbeiten mögen, sollten Sie an ihrem Namensraum sein kann , wird es oder andere scape Code, bevor Sie so Ihren Prozess starten, wie for loopoder find commandsetzen das IFS bash env variablean:

IFS=$(echo -en "\n\b")
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.