Je veux agir sur une liste de sous-répertoires dans un répertoire. Considérer:
for x in x86-headers/*/C/populate.sh; do echo $x; done
Cela donne
x86-headers/elf/C/populate.sh
x86-headers/gl/C/populate.sh
x86-headers/gmp/C/populate.sh
x86-headers/gnome2/C/populate.sh
x86-headers/gtk2/C/populate.sh
x86-headers/jni/C/populate.sh
x86-headers/libc/C/populate.sh
Mais je veux des valeurs qui correspond à la seconde partie du chemin,
elf
, gl
, etc. Je sais comment Supprimer le caractère x86-headers
.
for x in x86-headers/*/C/populate.sh; do i=${x##x86-headers/}; echo $i; done
qui donne
elf/C/populate.sh
gl/C/populate.sh
gmp/C/populate.sh
gnome2/C/populate.sh
gtk2/C/populate.sh
jni/C/populate.sh
libc/C/populate.sh
Je sais également comment supprimer les termes ultérieurs du chemin. C'est à dire en descendant d'un niveau:
cd x86-headers
for x in */C/populate.sh; do i=${x%%/*}; echo $i; done
donne
elf
gl
gmp
gnome2
gtk2
jni
libc
Mais essayer de les combiner ne fonctionne pas. C'est à dire
for x in x86-headers/*/C/populate.sh; do i=${${x##x86-headers}%%/*}; echo $i; done
donne
bash: ${${x##x86-headers}%%/*}: bad substitution
C'est sans doute une syntaxe incorrecte, mais je ne connais pas la syntaxe correcte. Bien sûr, il pourrait y avoir de meilleures façons de le faire. Si j'utilisais Python, j'utiliserais split on /
pour décomposer chaque chemin en une liste, puis choisir le deuxième élément, mais je ne sais pas comment faire cela en bash.
EDIT: Merci pour les réponses. J'aurais également dû demander, est-il possible de le faire de manière portable et si oui, comment?
i=${x#*/}; i=${i%%/*}
est facultatif, non?ash
/dash
exécuteraient les affectations de droite à gauche (ce qui était le comportement du shell Bourne) et causeraient des problèmes dans ce cas.L'expansion des paramètres ne vous permet pas d'imbriquer des expressions, vous êtes donc obligé de le faire en deux étapes, avec une affectation:
Vous avez la possibilité d'utiliser des tableaux ici, mais je pense que ce serait plus lourd que le PE ci-dessus:
Ensuite, il y a la troisième option d'utiliser des commandes externes. Avec une courte liste de fichiers, c'est généralement l'option la moins efficace, mais elle évoluera au mieux à mesure que le nombre de fichiers augmente:
la source
zsh
permet l'emboîtement.bash
.la source
Soyez très prudent en utilisant une construction comme ci-dessous:
Comme vous pourriez finir par faire un
echo *
. Dans ce cas, ce n'est que drôle, mais cela pourrait être bien pire si vous êtes root, votreCWD
est/
et que vous souhaitez supprimer certains sous-répertoires/tmp
au lieu de les répéter!Pour corriger cela dans bash, vous pouvez faire:
Remarquez
shopt -u nullglob
à la fin pour restaurer le comportement bash par défaut après la boucle.Une solution plus portable pourrait être:
(Les substitutions de paramètres
##
et%%
sont valides dans ksh88 ).Suivez ce lien pour une discussion plus complète de nullglob .
Notez que les 3 solutions ci-dessus échouent si vous avez un répertoire intermédiaire avec un espace dans son nom. Pour le résoudre, utilisez des guillemets doubles dans la substitution de variable:
la source
Pour effectuer une correspondance de modèle sur les noms de chemin de manière portable, vous pouvez définir la
IFS
variable shell sur/
puis utiliser l'expansion des paramètres shell.Faire tout cela dans un sous-shell aide à garder l'environnement du shell parent inchangé!
la source