J'ai le script bash simplifié suivant
#!/bin/bash
files=("$@")
if [ "X$files" = "X" ]; then
files=$HOME/print/*.pdf;
fi
for file in "${files[@]}"; do
ls "$file";
done
Si je passe des arguments (noms de fichiers) comme paramètres, ce script affichera les noms de fichiers appropriés. D'un autre côté, si je ne passe pas d'arguments, il affichera
/home/user/print/*.pdf: No such file or directory
Pourquoi les noms de fichiers ne sont-ils pas développés dans ce cas, et comment puis-je le corriger? Notez que j'utilise les constructions files=("$@")
et "${files[@]}"
parce que j'ai lu qu'il est préférable aux "fichiers = $ *" habituels.
files=$*
que c'est habituel ? C'est tout à fait faux .Réponses:
Vous attribuez
files
une variable scalaire au lieu d'une variable de tableau .Dans
Vous assignez une chaîne comme
/home/highsciguy/print/*.pdf
à la$files
variable scalaire (ou chaîne).Utilisation:
ou
au lieu. Le shell étendra ce modèle de globalisation dans une liste de chemins de fichiers et affectera chacun d'eux aux éléments du
$files
tableau .L'expansion du glob se fait au moment de l'affectation.
Vous n'avez pas besoin d'utiliser des fonctionnalités sh non standard, et vous pouvez utiliser celles de votre système à la
sh
place d'bash
ici en l'écrivant:set
consiste à affecter le"$@"
tableau de paramètres de position.Une autre approche aurait pu être de stocker le motif de globulation dans une variable scalaire:
Et que le shell développe le glob au moment où la
$files
variable est développée.Ici, parce qu'il
$files
n'est pas cité (ce que vous ne devriez généralement pas faire), son expansion est sujette au fractionnement de mots (que nous avons désactivé ici) et à la génération de globbing / nom de fichier.Ainsi, le
*.pdf
sera étendu à la liste des fichiers correspondants. Cependant, s'ils$HOME
contiennent des caractères génériques, ils peuvent également être développés, c'est pourquoi il est toujours préférable d'utiliser une variable de tableau.la source
Vous avez peut-être vu des choses comme
files=$*
etfiles=~/print/*.pdf
dans des coquilles plus anciennes sans tableaux, puisls $files
.Une substitution de variable qui n'est pas entre guillemets interprète la valeur de la variable comme une liste séparée par des espaces de motifs génériques de shell qui sont remplacés par des noms de fichiers correspondants s'il y en a. Par exemple, après
files=~/print/*.pdf
, sels $files
développe en quelque chose commels
avec les arguments/home/highsciguy/print/bar.pdf
,/home/highsciguy/print/foo.pdf
etc. Dans le casfiles=$*
, cette affectation concatène les arguments passés au script avec des espaces entre les deux et lesls $files
divise en arrière.Tout cela tombe en panne si vous avez des noms de fichiers contenant des espaces ou des caractères globbing, c'est pourquoi vous ne devriez pas faire les choses de cette façon. Utilisez plutôt des tableaux.
Notez que
var=(…)
."$files"
est vide quandfiles
est un tableau dont l'élément d'index 0 est non défini ou une chaîne vide. Il[ "X$foo" = "X" ]
existe également un moyen obsolète de tester s'il$foo
est vide: tous les shells modernes sont[ -n "$foo" ]
correctement mis en œuvre . En bash, vous pouvez utiliser[[ -n $foo ]]
.Dans les shells qui ne prennent pas en charge les tableaux, il existe en fait un tableau: les paramètres positionnels du shell ou la fonction courante. Ici, vous n'avez pas vraiment besoin du
files
tableau, en fait, il serait plus facile d'utiliser les paramètres positionnels.la source