Ich habe dieses Skript geschrieben:
#!/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
Ich bin ein Neuling, der versucht, schnell zu lernen, und ich habe eine Frage zu den Anführungszeichen der Variablen .
Setzen Sie eine Variable zwischen $ (), ich bekomme es, aber warum werden die Anführungszeichen auch in der if
Anweisung benötigt? Soll ein verschachtelter Befehl ausgeführt werden?
while [ true ]
dies eine Endlosschleife erzeugt, aber möglicherweise nicht aus dem Grund, den Sie glauben, dass dies der Fall ist.while [ false ]
Auch erzeugt eine Endlosschleife, weil mit einem einzigen Argumente,[ ... ]
gelingt es , wenn das Argument eine nicht leere Zeichenfolge ist.while true
wird tatsächlich einen Befehl namens ausführentrue
(der immer erfolgreich ist).$()
. Sie haben einen Befehl eingegeben$()
.Antworten:
Anführungszeichen verhindern "Wortteilung". Das heißt: Unterteilen von Variablen in mehrere Elemente mit Leerzeichen (oder genauer gesagt mit Leerzeichen, Tabulatoren und Zeilenumbrüchen, wie im Wert der Standard-
$IFS
Shell-Variablen definiert).Beispielsweise,
Hier definieren wir die
howmany
Funktion, mit der wir nur wissen, wie viele Positionsparameter angegeben sind. Wie Sie sehen, werden zwei Elemente an die Variable übergeben, und mit den Anführungszeichen wird der Text in der Variablen als eine Einheit behandelt.Dies ist wichtig für die korrekte Weitergabe von Informationen. Wenn die Variable beispielsweise den Pfad zur Datei enthält und der Dateiname an einer beliebigen Stelle im Pfad Leerzeichen enthält, schlägt der auszuführende Befehl möglicherweise fehl oder liefert ungenaue Ergebnisse. Wenn wir versuchen würden, eine Datei mit der
$var
Variablentouch $var
zu erstellen , würden wir zwei Dateien erstellen, abertouch "$var"
nur eine.Gleiches gilt für deinen
[ "$currentoutput" != "$lastoutput" ]
Teil. Dieser spezielle Test führt einen Vergleich mit zwei Zeichenfolgen durch. Wenn der Test ausgeführt wird, muss der[
Befehl drei Argumente anzeigen - eine Textzeichenfolge, den!=
Operator und eine andere Textzeichenfolge. Wenn Sie doppelte Anführungszeichen verwenden, wird die Wortteilung verhindert, und der[
Befehl erkennt genau diese drei Argumente. Was passiert nun, wenn Variablen nicht in Anführungszeichen gesetzt sind?Hier tritt Wort Spaltung und stattdessen
[
sieht zwei Saitenhello
undworld
gefolgt von!=
, gefolgt von zwei anderen Saitenhi world
. Entscheidend ist, dass der Inhalt von Variablen ohne doppelte Anführungszeichen als separate Einheiten und nicht als ein ganzes Element verstanden wird.Das Zuweisen der Befehlsersetzung erfordert keine doppelten Anführungszeichen wie in
wo Sie die
df
Ausgabe des Befehls gespeichert habenvar
. Es ist jedoch eine gute Angewohnheit, Variablen und Befehlsersetzungen immer in doppelte Anführungszeichen zu setzen, es sei$(...)
denn, Sie möchten, dass die Ausgabe als separate Elemente behandelt wird.Nebenbei bemerkt, die
Teil kann sein
[
ist ein Befehl, der seine Argumente auswertet und[ whatever ]
immer wahr ist, unabhängig davon, was sich darin befindet. Im Gegensatz dazuwhile true
wird der Befehl verwendet,true
der immer den Status "Erfolgreich beendet" zurückgibt (und genau daswhile
benötigt die Schleife). Der Unterschied ist ein bisschen mehr Klarheit und weniger Tests durchgeführt. Alternativ könnten Sie auch:
anstelle von verwendentrue
Die doppelten Anführungszeichen zum
echo "" date and Time
Teil könnten wahrscheinlich entfernt werden. Sie fügen lediglich eine leere Zeichenfolge ein und fügen der Ausgabe zusätzlichen Speicherplatz hinzu. Wenn Sie dies wünschen, können Sie sie dort aufbewahren, aber in diesem Fall gibt es keinen bestimmten funktionalen Wert.Dieser Teil könnte wahrscheinlich durch ersetzt werden
echo "$currentoutput" >> test.log
. Es gibt keinen Grund,lsusb
erneut zu starten , nachdem es bereits in ausgeführt wurdecurrentoutput=$(lsusb)
. In Fällen, in denen nachgestellte Zeilenumbrüche in der Ausgabe beibehalten werden müssen, kann der Wert durch mehrmaliges Ausführen eines Befehls angezeigt werden, dies ist jedochlsusb
nicht erforderlich. Je weniger externe Befehle Sie aufrufen, desto besser, da jeder Aufruf eines nicht integrierten Befehls Kosten für CPU, Speichernutzung und Ausführungszeit verursacht (obwohl die Befehle wahrscheinlich aus dem Speicher vorgeladen sind).Siehe auch:
quelle
bash
. Aber im letzten Teil sollte es nichtecho "$currentoutput" >> test.log
besser seinprintf '%s\n' "$currentoutput" >> test.log
?printf
sollte aus Gründen der Portabilität bevorzugt werden. Da wir hier bash-spezifisches Skript verwenden, kann es zur Verwendung entschuldigt werdenecho
. Aber Ihre Beobachtung ist sehr richtigecho
absolut zuverlässig ist, auch wenn bekannt ist, dass die Shell bash ist (und der Wert vonxpg_echo
undposix
Flags bekannt ist). Wenn Ihr Wert-n
oder sein könnte-e
, kann er verschwinden, anstatt gedruckt zu werden.In
currentoutput="$(lsusb)"
lsusb keine Variable ist, ist es ein Befehl. Diese Anweisung führt denlsusb
Befehl aus und weist die Ausgabe dercurrentoutput
Variablen zu.Ältere Syntax dafür war
Sie finden es in vielen Beispielen und Skripten
Um den anderen Teil Ihrer Frage zu beantworten,
if [ ]
wirdif
in bash lediglich die Syntax für definiert. Weitere Informationen finden Sie unter https://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.htmlquelle
[ ]
tatsächlich dertest
Befehl ist. Sie könnenif
Anweisungen auch mit anderen Befehlen verwenden, da sie auf einem 0- oder Nicht-Null-Test ihres Exit-Codes basieren.if grep -qe "somestring" file
als zu laufengrep -qe "somestring" file; if [ $? = 0 ]; then ...
, daher ist die Behauptung,if [ ...
die Teil der Definition vonif
Syntax ist, nicht nur irreführend, sondern führt zu schlechten Praktiken.Der folgende Befehl führt den externen Befehl aus
command
und gibt seine Ausgabe zurück.Ohne die Klammern würde dies nach einer Variablen suchen, anstatt einen Befehl auszuführen:
Der Unterschied zwischen
$variable
und"$variable"
wird relevant, wenn$variable
Leerzeichen enthalten sind. Bei der Verwendung"$variable"
wird der gesamte Variableninhalt in eine einzelne Zeichenfolge eingefügt, auch wenn der Inhalt Leerzeichen enthält. Bei der Verwendung kann$variable
der Inhalt der Variablen zu einer Argumentliste mit mehreren Argumenten erweitert werden.quelle
Um dagegen zu sein, empfiehlt bash, das
[[ ... ]]
over-the-[ ... ]
Konstrukt zu verwenden, um zu vermeiden, dass Variablen im Test in Anführungszeichen gesetzt werden müssen, und damit die damit verbundenen Probleme der Wortteilung, auf die die anderen hingewiesen haben.[
wird in bash bereitgestellt, um POSIX-Kompatibilität mit Skripten zu gewährleisten, die unter#!/bin/sh
bash ausgeführt oder nach bash portiert werden sollen. Sie sollten dies größtenteils vermeiden[[
.z.B
quelle
bash
gibt keine solche Empfehlung ab; Es bietet,[[ ... ]]
was bequemer sein kann und einige Funktionen hat,[ ... ]
die nicht, aber es gibt kein Problem mit der[ ... ]
richtigen Verwendung .[[
tut alles[
und noch mehr, und immer noch stolpert das viele Mal die[
Leute und versucht dann, Funktionen von[[
back to nachzurüsten, um[
nur zu versagen und Fehler zu hinterlassen Community-Empfehlungen in Bezug auf die meisten relevanten Bash-Style-Guides raten dazu, diese niemals zu verwenden[
.