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, desvariable
et des arithmétiques et substitution des commandes (effectuée de gauche à droite), fractionnement des mots etpathname 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 anti – modè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.