Napisałem ten skrypt:
#!/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
Jestem nowicjuszem, który próbuje szybko się uczyć i mam pytanie o cudzysłowy zmiennej .
Ustaw zmienną pomiędzy $ (), rozumiem, ale dlaczego znaki cudzysłowu są potrzebne nawet w if
instrukcji? Czy to polecenie zagnieżdżone?
while [ true ]
tworzy nieskończoną pętlę, ale być może nie z tego powodu, dla którego tak myślisz;while [ false ]
również produkuje nieskończoną pętlę, bo z jednym argumentem,[ ... ]
uda, jeśli ten argument jest niepusty ciąg.while true
rzeczywiście uruchomić polecenie nazwietrue
(które zawsze udaje).$()
. Wstawiłeś polecenie do środka$()
.Odpowiedzi:
Cudzysłowy uniemożliwiają „dzielenie słów”. To znaczy: dzielenie zmiennych na wiele elementów przy znakach spacji (a ściślej, w odstępach, tabulatorach i znakach nowej linii, jak określono w wartości domyślnej
$IFS
zmiennej powłoki).Na przykład,
Tutaj definiujemy
howmany
funkcję, która po prostu informuje nas o liczbie podanych parametrów pozycyjnych. Jak widać, do zmiennej przekazywane są dwa elementy, a wraz z cudzysłowami tekst w zmiennej jest traktowany jako jedna jednostka.Jest to ważne dla dokładnego przekazywania informacji. Na przykład, jeśli zmienna zawiera ścieżkę do pliku, a nazwa pliku zawiera spacje w dowolnym miejscu na ścieżce, polecenie, które próbujesz uruchomić, może zakończyć się niepowodzeniem lub dać niedokładne wyniki. Gdybyśmy próbowali utworzyć plik ze
$var
zmienną,touch $var
utworzylibyśmy dwa pliki, aletouch "$var"
tylko jeden.To samo dotyczy twojej
[ "$currentoutput" != "$lastoutput" ]
części. Ten konkretny test przeprowadza porównanie dwóch ciągów. Po uruchomieniu testu[
polecenie musi zobaczyć 3 argumenty - ciąg tekstowy,!=
operator i kolejny ciąg tekstowy. Trzymanie podwójnych cudzysłowów zapobiega dzieleniu słów, a[
polecenie rozpoznaje dokładnie 3 argumenty. Co się stanie, jeśli zmienne nie będą cytowane?Tutaj występuje dzielenie słów, a zamiast tego
[
widzimy dwa ciągi,hello
aworld
następnie!=
, a następnie dwa inne ciągihi world
. Kluczową kwestią jest to, że bez podwójnych cudzysłowów zawartość zmiennych należy rozumieć jako oddzielne jednostki, a nie jedną całość.Przypisanie podstawienia polecenia nie wymaga podwójnych cudzysłowów jak w
gdzie
df
zapisano dane wyjściowe poleceniavar
. Jednak dobrym zwyczajem jest zawsze podwójne cytowanie zmiennych i zastępowanie poleceń,$(...)
chyba że faktycznie chcesz, aby dane wyjściowe były traktowane jako osobne elementy.Na marginesie:
część może być
[
to polecenie, które ocenia jego argumenty i[ whatever ]
jest zawsze prawdziwe, niezależnie od tego, co jest w środku. Natomiastwhile true
używa polecenia,true
które zawsze zwraca status wyjścia pomyślnego zakończenia (i właśnie tegowhile
potrzebuje pętla). Różnica polega na nieco większej przejrzystości i mniejszej liczbie przeprowadzonych testów. Możesz też użyć:
zamiasttrue
Podwójne cytaty
echo "" date and Time
częściowo mogłyby zostać prawdopodobnie usunięte. Po prostu wstawiają pusty ciąg i dodają dodatkową przestrzeń do wyniku. Jeśli jest to pożądane, możesz je tam zachować, ale w tym przypadku nie ma żadnej szczególnej wartości funkcjonalnej.Ta część prawdopodobnie mogłaby zostać zastąpiona
echo "$currentoutput" >> test.log
. Nie ma powodu, aby uruchomićlsusb
ponownie po tym, jak już został uruchomionycurrentoutput=$(lsusb)
. W przypadkach, gdy końcowe znaki nowej linii muszą zostać zachowane na wyjściu - można było zobaczyć wartość przy wielokrotnym uruchamianiu polecenia, ale w przypadkulsusb
takiej potrzeby nie jest to konieczne. Im mniej wywołujesz zewnętrznych poleceń, tym lepiej, ponieważ każde wywołanie niewbudowanego polecenia powoduje koszty procesora, zużycia pamięci i czasu wykonania (nawet jeśli polecenia są prawdopodobnie wstępnie ładowane z pamięci).Zobacz też:
źródło
bash
. Ale w ostatniej części nie powinnoecho "$currentoutput" >> test.log
być lepiejprintf '%s\n' "$currentoutput" >> test.log
?printf
powinno być preferowane ze względu na przenośność. Ponieważ używamy tutaj skryptu specyficznego dla bash, można go usprawiedliwićecho
. Ale twoja obserwacja jest bardzo poprawnaecho
jest to całkowicie niezawodne, nawet jeśli wiadomo, że powłoka to bash (i znana jest wartość flagxpg_echo
iposix
); jeśli twoja wartość może wynosić-n
lub-e
, może zniknąć zamiast zostać wydrukowana.W
currentoutput="$(lsusb)"
lsusb nie jest zmienną, jest to polecenie. To, co robi ta instrukcja, wykonujelsusb
polecenie i przypisuje dane wyjściowe docurrentoutput
zmiennej.Była to starsza składnia
można go znaleźć w wielu przykładach i skryptach
Aby odpowiedzieć na drugą część pytania,
if [ ]
wystarczyif
zdefiniować składnię w bash. Zobacz więcej na https://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.htmlźródło
[ ]
tak naprawdę jest totest
polecenie. Możesz używaćif
instrukcji także z innymi poleceniami, ponieważ zależy to od 0 lub niezerowego testu ich kodu wyjścia.if grep -qe "somestring" file
niż biegaćgrep -qe "somestring" file; if [ $? = 0 ]; then ...
, więc twierdzenie, któreif [ ...
jest częścią definicjiif
składni, nie tylko wprowadza w błąd, ale prowadzi do złych praktyk.Poniżej uruchamia zewnętrzne polecenie
command
i zwraca jego wynik.Bez nawiasów / nawiasów szukałoby zmiennej zamiast uruchamiania polecenia:
Jeśli chodzi o różnicę między
$variable
i"$variable"
, staje się to istotne, gdy$variable
zawiera spacje. Podczas używania"$variable"
cała zawartość zmiennej zostanie wstawiona do jednego ciągu, nawet jeśli zawartość zawiera spacje. Podczas korzystania$variable
z zawartości zmiennej można rozwinąć listę argumentów zawierającą wiele argumentów.źródło
Być contrarian - bash zaleca użyć
[[ ... ]]
na[ ... ]
konstrukcie, aby uniknąć konieczności zacytować zmienne w teście, a więc związanych z tym problemów z podziałem na słowa, że inni zwrócili uwagę.[
jest zapewniony w bash dla zgodności z POSIX ze skryptami przeznaczonymi do uruchamiania#!/bin/sh
lub tymi, które są przenoszone do bash - w większości przypadków powinieneś tego unikać na korzyść[[
.na przykład
źródło
bash
nie daje takich zaleceń; zapewnia to,[[ ... ]]
co może być wygodniejsze i ma pewną funkcjonalność, która[ ... ]
tego nie robi, ale nie ma problemu z[ ... ]
prawidłowym użyciem .[[
robi wszystko[
i więcej, a mimo to wiele razy[
tripuje ludzi, a następnie próbuje i modernizuje funkcje z[[
powrotem[
tylko po to, aby zawieść i pozostawiać rozrzucone błędy - można powiedzieć, że jest to rekomendacje społeczności w zakresie, w jakim najbardziej odpowiednie przewodniki stylu bash zalecają nigdy nie używać[
.