Costruire percorsi in modo robusto


16

Supponiamo che io abbia diverse variabili in uno script di shell (ad es. In zsh):

FOLDER_1, FOLDER_2, etc.

Queste variabili si riferiscono a cartelle discendenti da /. Ad esempio, se ho un percorso/home/me/stuff/items

le variabili sarebbero:

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

Ora, dì che voglio ricostruire il percorso corrispondente concatenando le variabili. Un modo possibile è costruire il percorso come segue:

PATH=$FOLDER_1/$FOLDER_2/$FOLDER_3/

Tuttavia, supponiamo che alcune delle variabili presentino FOLDER_ibarre rovesciate, mentre altre no (e non sappiamo quale) ad es

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

La mia domanda è: come potrei costruire il percorso in modo robusto? (ad esempio evitando doppi tagli e aggiungendoli dove devono essere).

Ho pensato che un modo per farlo fosse quello di aggiungere /sempre le coppie di variabili e quindi eliminare tutti i duplicati sed, ma non riesco a farlo funzionare (non sono sicuro che sto gestendo /correttamente sed).

Inoltre, sto reinventando la ruota ? (cioè c'è qualche built-in che lo fa già?).

In definitiva, se le variabili sono in un array , ad esempio FOLDERS, sarebbe possibile farlo senza loop? (o in alternativa, eseguendo il loop ma senza sapere quanti FOLDERSce ne sono nell'array).

Risposte:


12

È possibile utilizzare printfcon un array:

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

L' %operatore taglia le stringhe finali, in questo caso /. Applicandolo a parts[@], ritaglia ogni membro dell'array separatamente.

La chiave per comprendere questo printftrucco, è questa man 1 printf: "La stringa di formato viene riutilizzata tutte le volte che è necessario per soddisfare gli argomenti".


Il %metodo singolo funziona per la singola barra finale menzionata nel queston. Per soddisfare quando ci sono più barre, ${parts[@]%%/*}funziona. Ecco un link a qualche informazione in più sul problema della barra: Cosa significano le doppie barre nel percorso UNIX? È 'cd dir / subdir // valido ...
— Peter.O

2
@fered: /*in questo caso non significa zero o più barre , ma piuttosto una barra seguita da un numero qualsiasi di caratteri. Ciò significa che se il percorso inizia con una barra, il risultato sarà la stringa vuota!
— l0b0,

Avevo considerato, come nell'esempio, che ci sarebbero state solo barre finali. Tuttavia, per adattarsi alla possibilità di una (e) extglobshopt -s extglob; ${parts[@]%%/+(/)}
— bara

15

La semplice risposta è smettere di preoccuparsi e amare più barre. Le barre multiple hanno lo stesso effetto di una barra singola (tranne per il fatto che un percorso che inizia con //un significato diverso su alcuni sistemi; i livelli di emulazione unix su Windows sono gli unici che posso nominare). È in base alla progettazione e la possibilità di assemblare i nomi dei file senza doversi preoccupare di più barre è stata una parte importante di quella decisione di progettazione.

Per unire gli elementi dell'array, in zsh, è possibile utilizzare il j flag di espansione dei parametri .

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

Puoi schiacciare le doppie barre mentre ci sei, ma è puramente cosmetico.

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

In ksh e bash, puoi unire un array usando il primo carattere di $IFScome separatore. È quindi possibile schiacciare le barre duplicate. In bash, dovrai fare shopt -s extglobper abilitare i globs ksh nell'ultima riga dello snippet di seguito.

IFS=/
dir="${FOLDERS[*]}"
unset IFS
dir=${dir//\/+(\/)//}

3

Come sednon funziona per te? Prova sed 's|/\+|/|g'dopo la concatenazione o sed 's|/||g'prima.


1

bash 4introdotto il globbing esteso, che consente la corrispondenza delle espressioni regolari nella sostituzione dei parametri ${var....}... È disattivato per impostazione predefinita. Per abilitarlo per il tuo script, imposta semplicemente l'opzione shell extglob ...

Supponendo che $ dir ==/home/me/////////stuff//items

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

Valore risultante di $ dir

/home/me/stuff/items  

Ecco alcuni esempi di cose da fare e da non fare: Bash Extended Globbing

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.