J'ai un script shell nommé 'teleport.sh' comme ceci:
if [ $1="1" ];
then
shift
mv "$@" ~/lab/Sun
elif [ $1="2" ];
then
shift
mv "$@" ~/lab/Moon
elif [ $1="3" ];
then
shift
mv "$@" ~/lab/Earth
fi
Quand j'exécute:
sh teleport.sh 2 testfile
Ceci testfile
est déplacé vers le ~/lab/Sun
répertoire, ce qui me déroute beaucoup car je n'ai pas passé 1 ou '1' à ce script.
Qu'est-ce qui ne va pas ici?
$var
,$(cmd)
et même`cmd`
[auquel$(cmd)
devrait être préféré]). Il y a des cas limites où vous ne devez citer, mais toujours le faire ne fera pas mal.$(cmd)
est la substitution de commande , (la plupart du temps) identique à`cmd`
. Voir mywiki.wooledge.org/CommandSubstitution et mywiki.wooledge.org/BashFAQ/082Réponses:
L'utilisation d'espaces résout votre problème.
Bien que ce soit plus propre:
la source
$1="1"
syntaxe originale "fonctionne" du tout (produisant un vrai résultat). Comment le[
/test
builtin interprète-t-il réellement cette expression?test
ne voit qu'un seul argument (une "valeur l"). Sans les autres arguments (un "opérateur" et une "valeur r"), il n'y a rien à tester, donctest
dit simplement "ok, ben ouais, tu m'as donné quelque chose et cela doit être vide."$1="1"
est$1
concaténé par=1
La première chose évidente est que vous devez fournir des espaces entre les arguments de
[
,test
ou[[
:Dans Bash, l'utilisation
[[ ]]
est recommandée car elle ne fait pas de choses inutiles pour l'expression conditionnelle comme le fractionnement de mots et l'expansion de noms de chemin. Il n'est pas non plus nécessaire de citer des guillemets doubles. Un opérateur plus lisible==
peut également être utilisé.Ajout d'une note: Si un deuxième opérande contient également des variables, citant est nécessaire car il peut être soumis à la correspondance de motif si elle contient des caractères reconnaissables comme
*
,?
,[]
, etc .. si elle était étendue englobement ou correspondance de motif est activé avecshopt -s extglob
, d' autres formes comme@()
,!()
, etc. seront également reconnus comme des modèles. Voir Correspondance de motifs .Avec des opérateurs comme
<
et>
cela peut encore être nécessaire car j'avais rencontré un bug où ne pas citer le deuxième argument provoquait des résultats différents.Quant au premier opérande, rien ne s'applique.
Considérez également cette variante plus simple:
Ou condensé:
"${@:2}"
est une forme d'extension de sous-chaîne ou d'extension de membre de tableau où2
est le décalage. Cela fait démarrer l'expansion à la deuxième valeur. Avec cela, nous n'aurons peut-être pas besoin d'utilisershift
.L'ajout
--
empêchemv
de reconnaître les noms de fichiers commençant par dash (-
) comme des options invalides.la source
;&
place de;;
(ksh, bash, zsh uniquement). Mais alorsbreak
n'empêche toujours pas la chute,break
c'est seulement pour sortir des boucles.if
mais la[
commande.[[ $foo == $bar ]]
effectuera une correspondance de modèle, mais[[ $foo == "$bar" ]]
ne le fera pas.Pour répondre à la question de savoir pourquoi cela se produit, ce comportement de
[
akatest
est documenté dans POSIX :Vous lui passez 1 argument,
2=1
qui n'est pas nul, et setest
termine donc avec succès.Comme le soulignent d'autres articles (et shellcheck ), si vous souhaitez comparer pour l'égalité, vous devrez plutôt passer les 3 arguments
2
,=
et1
.la source
Je veux juste recommander une alternative portable mais aussi plus soignée. Bash n'est pas universel (et si vous n'avez pas besoin d'universel, pourquoi écrivez-vous un script shell?)
(Remarque pour les pédants: oui, je sais que les citations
$action
sur lacase "$action" in
ligne sont inutiles, mais je pense qu'il est préférable de les mettre de toute façon, afin que les futurs lecteurs n'aient pas à s'en souvenir.)la source
/bin/sh
scripts portables , si vous en avez besoin; sinon, écrivez dans un langage de script moins terrible que shell. L'interpréteur Perl de base est en fait plus susceptible d'être présent dans les environnements propriétaires hérités et les environnements intégrés réduits que Bash.