Comment atsortingbuer une expression de globule à une variable dans un script Bash?

Lorsque les deux lignes de code suivantes sont exécutées dans un script bash, “ls” se plaint que les fichiers n’existent pas:

dirs=/content/{dev01,dev02} ls -l $dirs 

Lorsque j’exécute le script avec l’option -x, il semble que la variable passe entre guillemets simples (ce qui empêcherait la globalisation):

 + dirs=/content/{dev01,dev01} + ls -l '/content/{dev01,dev01}' ls: /content/{dev01,dev01}: No such file or directory 

Si j’exécute la commande “ls” à partir de mon shell interactif (sans guillemets), elle renvoie les deux répertoires.

J’ai lu le Manuel de référence de Bash (v 3.2) et je ne vois aucune raison pour que le nom du fichier ne soit pas généré (je ne transmets pas -f au shell), ou tout ce que je peux définir pour vérifier que globbing arrive.

Je pense que c’est l’ordre des extensions:

L’ordre des extensions est: brace expansion tilde, expansion des parameters, des variable et des arithmétiques et substitution des commandes (effectuée de gauche à droite), fractionnement des mots et pathname expansion .

Donc, si votre variable est substituée, l’expansion des accolades n’a plus lieu. Cela fonctionne pour moi:

 eval ls $dirs 

Soyez très prudent avec eval. Il va exécuter les choses intégralement. Donc si dirs contient f{m,k}t*; some_command f{m,k}t*; some_command , some_command sera exécuté après la fin du ls. Il exécutera la chaîne que vous donnerez à eval dans le shell actuel. Il transmettra /content/dev01 /content/dev02 à ls, qu’elles existent ou non. Placer * après le truc en fait une extension de chemin, et omettra les chemins non existants:

 dirs=/content/{dev01,dev02}* 

Je ne suis pas sûr à 100%, mais cela a du sens pour moi.

Voici une excellente discussion sur ce que vous essayez de faire.

La réponse courte est que vous voulez un tableau:

 dirs=(/content/{dev01,dev01}) 

Mais ce que vous faites avec les résultats peut devenir plus complexe que ce que vous visiez, je pense.

Ce n’est pas un nom de fichier, c’est une extension d’accolade. La différence est subtile, mais elle existe – dans la mise en nom de fichier, vous ne recevez que les fichiers existants, alors que dans l’extension accolade, vous pouvez générer n’importe quel type de chaîne.

http://www.gnu.org/software/bash/manual/bashref.html#Brace-Expansion

http://www.gnu.org/software/bash/manual/bashref.html#Filename-Expansion

Maintenant, c’est ce qui a fonctionné pour moi:

 #!/bin/sh dirs=`echo ./{dev01,dev02}` ls $dirs 

Pour les gens (comme moi), trouver ceci via Google, les réponses de @Peter et @ feoh sont la solution générale à “Comment globaliser les variables en script bash”.

 list_of_results=(pattern) 

va enregistrer les noms de fichiers existants correspondant au pattern dans le tableau list_of_results . Chaque élément de list_of_results contiendra un nom de fichier, des espaces et tout.

Vous pouvez accéder à chaque résultat sous la forme "${list_of_results[]}" pour partir de 0. Vous pouvez obtenir la liste complète, correctement citée, sous la forme "${list_of_results[@]}" .

Je soupçonne que ce dont vous avez besoin est un tableau, mais cela vous restreindra aux nouvelles bases. C’est plus économique que d’utiliser eval.

 dirs=( /"content with spaces"/{dev01,dev02} ) dirs=( /content/{dev01,dev02} ) ls -l "${dirs[@]}" 

 /content/{dev01,dev02} 

étendra à:

 "/content/dev01" "/content/dev02" 

L’existence de ces répertoires est sans importance pour l’expansion.

Cela devient imprévisible lorsque vous affectez une variable à une extension d’accolade.

 dirs=/content/{dev01,dev02} 

peut se transformer en

 "/content/dev01" 

ou

 "/content/dev01 /content/dev02" 

ou

 "/content/dev01" "/content/dev02" 

ou

 "/content/{dev01,dev02}" 

Si vous citez les accolades de quelque manière que ce soit, elles ne se développeront pas. Le résultat contiendra donc les accolades et sera pour la plupart dénué de sens.

Comme vous voulez globaliser les fichiers, vous ne devez pas utiliser les extensions d’accolades. Dans ce cas, l’utilisation de l’extension d’accolade est un antimodèle et certainement le mauvais outil pour le travail.

Qu’est-ce que vous voulez est étendu globbing :

 shopt -s extglob # likely already set in interactive shells dirs=/content/@(dev01|dev02) ls $dirs 
 ls `echo $dirs` 

travaille sous cygwin.