J'ai écrit ce script:
#!/bin/bash
while [ true ]
do
currentoutput="$(lsusb)"
if [ "$currentoutput" != "$lastoutput" ]
then
echo "" date and Time >> test.log
date +%x_r >> test.log
lastoutput="$(lsusb)"
lsusb >> test.log
fi
sleep 5
done
Je suis un débutant qui essaie d'apprendre rapidement et j'ai une question sur les guillemets de la variable .
Mettez une variable entre $ (), je comprends, mais pourquoi les guillemets sont-ils nécessaires même dans l' if
instruction? Est-ce pour faire une commande imbriquée?
while [ true ]
cela produit une boucle infinie, mais peut-être pas pour la raison pour laquelle vous pensez que c'est le cas; produitwhile [ false ]
également une boucle infinie, car avec un seul argument,[ ... ]
réussit si cet argument est une chaîne non vide. exécutera enwhile true
fait une commande nommée (qui réussit toujours).true
$()
. Vous mettez une commande à l' intérieur$()
.Réponses:
Les guillemets empêchent la "division des mots". C'est-à-dire: décomposer les variables en plusieurs éléments au niveau des espaces (ou pour être plus exact, aux espaces, tabulations et sauts de ligne tels que définis dans la valeur de la
$IFS
variable shell par défaut ).Par exemple,
Ici, nous définissons la
howmany
fonction qui nous permet juste de savoir combien de paramètres de position sont donnés. Comme vous pouvez le voir, deux éléments sont passés à la variable et, avec les guillemets, le texte de la variable est traité comme une seule unité.Ceci est important pour une transmission précise des informations. Par exemple, si la variable contient le chemin d'accès au fichier et que le nom de fichier contient des espaces n'importe où dans le chemin d'accès, la commande que vous essayez d'exécuter peut échouer ou donner des résultats inexacts. Si nous essayions de créer un fichier avec la
$var
variable,touch $var
créerait deux fichiers, maistouch "$var"
un seul.Il en va de même pour votre
[ "$currentoutput" != "$lastoutput" ]
part. Ce test particulier effectue une comparaison sur deux chaînes. Lorsque le test s'exécute, la[
commande doit voir 3 arguments - une chaîne de texte, l'!=
opérateur et une autre chaîne de texte. Garder les guillemets doubles empêche le fractionnement des mots et la[
commande voit exactement ces 3 arguments. Maintenant, que se passe-t-il si les variables ne sont pas citées?Ici, le fractionnement de mot se produit et
[
voit à la place deux chaîneshello
etworld
suivi de!=
, suivi de deux autres chaîneshi world
. Le point clé est que, sans guillemets doubles, le contenu des variables est compris comme des unités distinctes plutôt que comme un élément entier.L'attribution d'une substitution de commande ne nécessite pas de guillemets doubles comme dans
où vous avez
df
enregistré la sortie de la commandevar
. Cependant, c'est une bonne habitude de toujours doubler les variables entre guillemets et la substitution de commandes,$(...)
sauf si vous voulez en fait que la sortie soit traitée comme des éléments distincts.En passant, le
une partie peut être
[
est une commande qui évalue ses arguments et[ whatever ]
est toujours vraie indépendamment de ce qu'il y a à l'intérieur. En revanche,while true
utilise la commandetrue
qui renvoie toujours le statut de sortie de réussite (et c'est exactement ce dont lawhile
boucle a besoin). La différence est un peu plus de clarté et moins de tests effectués. Alternativement, vous pouvez également utiliser:
au lieu detrue
Les doubles guillemets
echo "" date and Time
pourraient en partie être supprimés. Ils insèrent simplement une chaîne vide et ajoutent un espace supplémentaire à la sortie. Si vous le souhaitez, n'hésitez pas à les conserver, mais il n'y a pas de valeur fonctionnelle particulière dans ce cas.Cette partie pourrait probablement être remplacée par
echo "$currentoutput" >> test.log
. Il n'y a aucune raison delsusb
recommencer après qu'il ait déjà été exécutécurrentoutput=$(lsusb)
. Dans les cas où les retours à la ligne doivent être conservés dans la sortie - on peut voir la valeur de l'exécution d'une commande plusieurs fois, mais dans le cas contraire,lsusb
cela n'est pas nécessaire. Moins vous appelez de commandes externes, mieux c'est, car chaque appel à une commande non intégrée entraîne des coûts de CPU, d'utilisation de la mémoire et de temps d'exécution (même si les commandes sont probablement préchargées depuis la mémoire).Voir également:
la source
bash
. Mais dans la dernière partie, ça ne devrait pasecho "$currentoutput" >> test.log
être mieuxprintf '%s\n' "$currentoutput" >> test.log
?printf
devrait être préféré pour la portabilité. Puisque nous utilisons ici un script spécifique à bash, il peut être excusé pour l'utiliserecho
. Mais votre observation est tout à fait correcteecho
soit complètement fiable même lorsque le shell est connu pour être bash (et que la valeur des drapeauxxpg_echo
etposix
est connue); si votre valeur peut être-n
ou-e
, elle peut disparaître au lieu d'être imprimée.Dans
currentoutput="$(lsusb)"
lsusb n'est pas une variable, c'est une commande. Ce que fait cette instruction, elle exécute lalsusb
commande et affecte sa sortie à lacurrentoutput
variable.Une syntaxe plus ancienne pour cela était
vous pouvez le trouver dans de nombreux exemples et scripts
Pour répondre à l'autre partie de votre question,
if [ ]
voici comment la syntaxe deif
est définie dans bash. Voir plus dans https://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.htmlla source
[ ]
c'est en fait latest
commande. Vous pouvez également utiliser desif
instructions avec d'autres commandes, car elles reposent sur un test 0 ou non nul de leur code de sortie.if grep -qe "somestring" file
que exécutergrep -qe "somestring" file; if [ $? = 0 ]; then ...
, donc l'affirmation quiif [ ...
fait partie de la définition de laif
syntaxe n'est pas seulement trompeuse mais conduit à de mauvaises pratiques.Ce qui suit exécute la commande externe
command
et renvoie sa sortie.Sans les crochets / parenthèses, cela rechercherait une variable au lieu d'exécuter une commande:
Quant à la différence entre
$variable
et"$variable"
, elle devient pertinente lorsque$variable
contient des espaces. Lors de l'utilisation"$variable"
, le contenu entier de la variable sera inséré dans une seule chaîne même si le contenu comprend des espaces. Lors de l'utilisation$variable
du contenu de la variable peut être développé dans une liste d'arguments de plusieurs arguments.la source
Pour être à contre-courant - bash vous recommande d'utiliser la construction
[[ ... ]]
over[ ... ]
pour éviter d'avoir à citer des variables dans le test et donc les problèmes associés de séparation de mots que les autres ont signalés.[
est fourni en bash pour la compatibilité POSIX avec les scripts destinés à être exécutés sous#!/bin/sh
ou ceux qui sont portés sur bash - pour la plupart, vous devriez l'éviter en faveur de[[
.par exemple
la source
bash
ne fait pas une telle recommandation; il fournit[[ ... ]]
ce qui peut être plus pratique et possède certaines fonctionnalités qui[ ... ]
ne le font pas, mais il n'y a aucun problème à l'utiliser[ ... ]
correctement .[[
que tout le[
fait et plus encore, les nombreuses fois[
déclenchent les gens et essaient ensuite de moderniser les fonctionnalités de[[
back to[
seulement pour échouer et laisser des bugs dispersés - il est juste de dire que c'est un recommandation de la communauté dans la mesure où les guides de style bash les plus pertinents conseillent de ne jamais les utiliser[
.