Pfade robust bauen

16

Angenommen, ich habe mehrere Variablen in einem Shell-Skript (z. B. in zsh):

FOLDER_1, FOLDER_2, etc.

Diese Variablen beziehen sich auf Ordner absteigend /. Zum Beispiel, wenn ich einen Pfad habe/home/me/stuff/items

Die Variablen wären:

FOLDER_1='home'
FOLDER_2='me'
FOLDER_3='stuff'

Angenommen, ich möchte den entsprechenden Pfad durch Verketten der Variablen wiederherstellen. Eine Möglichkeit besteht darin, den Pfad wie folgt zu erstellen:

PATH=$FOLDER_1/$FOLDER_2/$FOLDER_3/

Nehmen wir jedoch an, dass einige der Variablen FOLDER_imit Schrägstrichen versehen sind, während andere dies nicht tun (und wir nicht wissen, welche), z

FOLDER_1='home'
FOLDER_2='stuff/'
FOLDER_3='items'

Meine Frage ist: Wie könnte ich den Weg robust bauen? (zB vermeiden Sie doppelte Schrägstriche und fügen Sie sie hinzu, wo sie sein müssen).

Ich dachte, eine Möglichkeit, dies zu tun, besteht darin, /immer zwischen Variablenpaaren einzufügen und dann alle Duplikate mit zu löschen sed, aber ich kann es nicht zum Laufen bringen (ich bin mir nicht sicher, ob ich /richtig damit umgehe sed).

Außerdem erfinde ich das Rad neu ? (dh gibt es schon einen eingebauten, der das macht?).

Wenn sich die Variablen beispielsweise in einem Array befinden , FOLDERSwäre es dann möglich, dies ohne Schleifen auszuführen ? (oder alternativ durch Schleifen, ohne zu wissen, wie viele FOLDERSsich im Array befinden).

Amelio Vazquez-Reina
quelle

Antworten:

12

Sie können printfmit einem Array verwenden:

parts=("$FOLDER_1" "$FOLDER_2" "$FOLDER_3");
printf '/%s' "${parts[@]%/}"
# Use "printf -v path" to save it into a variable called "path" instead of printing it

In %diesem Fall schneidet der Operator nachgestellte Zeichenfolgen /. Durch Anwenden auf parts[@]wird jedes Arraymitglied separat zugeschnitten.

Der Schlüssel zum Verständnis dieses printfTricks ist dieses Bit aus man 1 printf: "Die Formatzeichenfolge wird so oft wie nötig wiederverwendet, um die Argumente zu erfüllen."

janmoesen
quelle
Die Einzelmethode %funktioniert für den einzelnen abschließenden Schrägstrich, der im Quest erwähnt wird. Funktioniert, wenn mehrere Schrägstriche vorhanden sind ${parts[@]%%/*}. Hier ist ein Link zu weiteren Informationen zum Thema Schrägstrich: Was bedeuten doppelte Schrägstriche im UNIX-Pfad? Ist 'cd dir / subdir // valid ...
Peter.O
2
@fered: bedeutet /*in diesem Fall nicht null oder mehr Schrägstriche , sondern einen Schrägstrich gefolgt von einer beliebigen Anzahl von Zeichen. Das heißt, wenn Ihr Pfad mit einem Schrägstrich beginnt, ist das Ergebnis die leere Zeichenfolge!
l0b0
Ich hatte nach dem Beispiel angenommen, dass es nur Schrägstriche geben würde. Um jedoch die Möglichkeit eines führenden Schrägstrich (n), bash anzupassen extglob(mit Regex) durch verwendet .. shopt -s extglob; ${parts[@]%%/+(/)}...
Peter.O
15

Die einfache Antwort ist, keine Sorgen mehr zu machen und mehrere Schrägstriche zu lieben. Mehrere Schrägstriche haben den gleichen Effekt wie ein einzelner Schrägstrich (außer dass ein Pfad, der mit beginnt, //auf einigen Systemen eine andere Bedeutung hat; Unix-Emulationsebenen unter Windows sind die einzigen, die ich benennen kann). Das ist beabsichtigt, und die Fähigkeit, Dateinamen zusammenzusetzen, ohne sich um mehrere Schrägstriche kümmern zu müssen, war ein wesentlicher Teil dieser Entwurfsentscheidung.

Um Array-Elemente in zsh zu verbinden, können Sie das j Parameter-Erweiterungs-Flag verwenden .

dir=${(j:/:)FOLDERS}

Sie können die doppelten Schrägstriche quetschen, wenn Sie gerade dabei sind, aber das ist rein kosmetisch.

setopt extended_glob
dir=${${(j:/:)FOLDERS}//\/\/##/\/}

In ksh und bash können Sie ein Array mit dem ersten Zeichen von $IFSals Trennzeichen verbinden. Sie können dann die doppelten Schrägstriche zerquetschen. In bash müssen Sie shopt -s extglobdie ksh-Globs in der letzten Zeile des folgenden Snippets aktivieren.

IFS=/
dir="${FOLDERS[*]}"
unset IFS
dir=${dir//\/+(\/)//}
Gilles 'SO - hör auf böse zu sein'
quelle
3

Wie geht sedes dir nicht? Versuchen Sie es sed 's|/\+|/|g'nach der Verkettung oder sed 's|/||g'vorher.

Kevin
quelle
1

bash 4Erweitertes Globbing eingeführt, das den Abgleich von regulären Ausdrücken bei der Parametersubstitution ermöglicht ${var....}... Es ist standardmäßig deaktiviert. Um es für Ihr Skript zu aktivieren, setzen Sie einfach die Shell-Option extglob ...

Angenommen, $ dir ==/home/me/////////stuff//items

shopt -s extglob; dir="${dir//+(\/)//}"

Resultierender Wert von $ dir

/home/me/stuff/items  

Hier sind einige Beispiele mit do-s und-don't-s - Bash Extended Globbing

Peter.O
quelle