Construire des chemins de façon robuste

16

Disons que j'ai plusieurs variables dans un script shell (par exemple dans zsh):

FOLDER_1, FOLDER_2, etc.

Ces variables font référence aux dossiers qui descendent /. Par exemple, si j'ai un chemin/home/me/stuff/items

les variables seraient:

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

Maintenant, disons que je veux reconstruire le chemin correspondant en concaténant les variables. Une façon possible consiste à créer le chemin comme suit:

PATH=$FOLDER_1/$FOLDER_2/$FOLDER_3/

Cependant, disons que certaines variables FOLDER_isont accompagnées de barres obliques de fin, tandis que d'autres ne le font pas (et nous ne savons pas lesquelles), par exemple

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

Ma question est: comment pourrais-je construire le chemin de manière robuste? (par exemple, éviter les doubles barres obliques et les ajouter là où elles doivent être).

J'ai pensé qu'une façon de le faire est d'ajouter le /toujours entre des paires de variables, puis de supprimer tous les doublons avec sed, mais je ne peux pas le faire fonctionner (je ne suis pas sûr de gérer /correctement sed).

Aussi, est -ce que je réinvente la roue ? (c.-à-d. y a-t-il une fonction intégrée qui le fait déjà?).

Enfin, si les variables sont dans un tableau , par exemple FOLDERS, serait-il possible de le faire sans boucle? (ou alternativement, en boucle mais sans savoir combien FOLDERSil y en a dans le tableau).

Amelio Vazquez-Reina
la source

Réponses:

12

Vous pouvez utiliser printfavec un tableau:

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' %opérateur ajuste les chaînes de fin, dans ce cas /. En l'appliquant à parts[@], il ajuste chaque membre du tableau séparément.

La clé pour comprendre cette printfastuce, est ce morceau de man 1 printf: "La chaîne de format est réutilisée aussi souvent que nécessaire pour satisfaire les arguments."

janmoesen
la source
La %méthode unique fonctionne pour la barre oblique finale mentionnée dans le queston. Pour répondre lorsqu'il y a plusieurs barres obliques, ${parts[@]%%/*}fonctionne. Voici un lien vers un peu plus d'informations sur le problème des barres obliques: que signifient les doubles barres obliques dans le chemin UNIX? 'Cd dir / subdir // est-il valide ...
Peter.O
2
@fered: /*dans ce cas, ne signifie pas zéro ou plusieurs barres obliques , mais plutôt une barre oblique suivie d'un nombre quelconque de caractères. Cela signifie que si votre chemin commence par une barre oblique, le résultat sera la chaîne vide!
l0b0
J'avais considéré, selon l'exemple, qu'il n'y aurait que des barres obliques de fin. Cependant, pour s'adapter à la possibilité d'une ou de plusieurs extglobshopt -s extglob; ${parts[@]%%/+(/)}
barres obliques
15

La réponse simple est d'arrêter de s'inquiéter et d'aimer plusieurs barres obliques. Plusieurs barres obliques ont le même effet qu'une seule barre oblique (sauf qu'un chemin commençant par //a une signification différente sur quelques systèmes; les couches d'émulation Unix sous Windows sont les seules que je peux nommer). C'est par conception, et pouvoir assembler des noms de fichiers sans avoir à se soucier de plusieurs barres obliques était une partie importante de cette décision de conception.

Pour joindre des éléments de tableau, dans zsh, vous pouvez utiliser l' j indicateur d'extension de paramètre .

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

Vous pouvez écraser les barres obliques en double pendant que vous y êtes, mais c'est purement cosmétique.

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

Dans ksh et bash, vous pouvez joindre un tableau en utilisant le premier caractère de $IFScomme séparateur. Vous pouvez ensuite écraser les barres obliques en double. En bash, vous devrez faire shopt -s extglobpour activer les globes ksh dans la dernière ligne de l'extrait ci-dessous.

IFS=/
dir="${FOLDERS[*]}"
unset IFS
dir=${dir//\/+(\/)//}
Gilles 'SO- arrête d'être méchant'
la source
3

Comment ça sedne marche pas pour vous? Essayez sed 's|/\+|/|g'après la concaténation ou sed 's|/||g'avant.

Kevin
la source
1

bash 4introduit le globbing étendu, qui permet la correspondance des expressions régulières dans la substitution de paramètres ${var....}... Il est désactivé par défaut. Pour l'activer pour votre script, définissez simplement l'option shell extglob ...

En supposant que $ dir ==/home/me/////////stuff//items

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

Valeur résultante de $ dir

/home/me/stuff/items  

Voici quelques exemples de choses à faire et à ne pas faire - Bash Extended Globbing

Peter.O
la source