Jaka jest różnica między echo „data”, echo „data” i echo „data”?


23

Jaka jest różnica między tymi trzema poleceniami?

echo `date`
echo "`date`"
echo '`date`'

Jestem zdezorientowany, jakie faktycznie są różnice. Wydaje mi się, że gdy „wokół” są, oznacza to, że jest to ciąg znaków, dlatego echo dosłownie wyświetli ciąg datezamiast wyświetlać datę?

Odpowiedzi:


19

`date` po prostu rozwinie się do wyjścia datepolecenia. Jednak usuwa dodatkowe znaki spacji w miejscach, w których na wyjściu znajduje się więcej niż jeden znak spacji. (Dzieje się tak, ponieważ podstawienie polecenia podlega podziałowi słów oraz temu, jak echopolecenie obsługuje wiele argumentów).

W „date” podwójne cudzysłowy są słabymi cudzysłowami, więc rozwiną zmienne (spróbuj „$ PWD”) i wykonają zamianę poleceń. Wynik rozwinięcia jest przekazywany do polecenia jako pojedynczy argument echo, z uwzględnieniem kolejnych spacji: to znaczy dzielenie słów nie jest wykonywane.

W `` date '' pojedyncze cudzysłowy są silniejszymi, więc nie pozwolą na rozszerzenie zmiennych lub podstawianie poleceń w nich.

Więcej informacji można znaleźć pod tym linkiem .

Zredagowano pierwszy punkt, jak prawidłowo wskazał Michael Suelmann w komentarzu poniżej .


1
Jak dokładnie nazywa się „znak otaczający datę? Jeśli dobrze rozumiem, metaznaki nie będą działać w pojedynczych cudzysłowach?
Jan

Jeśli dobrze rozumiem, metaznaki nie będą działać w pojedynczych cudzysłowach?
Jan

8
W tym scenariuszu „często nazywany jest„ backtick ”i różnymi dokumentacjami / książkami uniksowymi. W rzeczywistości nie jest używany jako poważny akcent Unicode, gdy jest sam w sobie, mimo że tak nazywa się ten symbol. I masz rację, że nie pojawi się rozwinięcie metaznaków / wyrażeń, jeśli otoczysz je pojedynczymi cudzysłowami.
Jim Stewart

Twoje pierwsze zdanie jest niepoprawne, ponieważ wyniki mogą się nieznacznie różnić w zależności od daty lub ustawień regionalnych. Tylko drugie polecenie wyświetli to samo, co samo datepolecenie.
jlliagre

1
@BonsiScott Dodatkowa spacja między „Nov” a „1” jest również usuwana w HTML;)
Izkata

16

Obie

echo `date`

i

echo "`date`"

wyświetli datę. Dane wyjściowe z tego ostatniego wyglądają jak dane wyjściowe z datesamego działania.

Jest jednak różnica: ten otoczony "cytatami "zostanie wysłany echojako pojedynczy argument. Cytaty zawierają wynik całej komendy jako jeden argument. Ponieważ echopo prostu wypisuje swoje argumenty w kolejności, ze spacjami między nimi, w zasadzie będzie wyglądać tak samo.

Oto przykład subtelnej różnicy:

echo `date`

produkuje:

Fri Nov 1 01:48:45 EST 2013

ale:

echo "`date`"

produkuje:

Fri Nov  1 01:48:49 EST 2013

Zauważ, że dwa kolejne spacje Novzostały zredukowane do jednego bez cudzysłowów. Wynika to z tego, że powłoka analizuje każdy element oddzielony spacją i wysyła wynik do echa jako 6 argumentów. Kiedy go zacytujesz, echo otrzymuje pojedynczy argument, a cytaty zachowują spację.

Staje się to o wiele ważniejsze w poleceniach innych niż echo. Na przykład wyobraź sobie polecenie, fooktóre chce dwóch argumentów: daty i adresu e-mail.

Będzie to działać w tym scenariuszu:

foo "`date`" joeuser@example.com

Spowoduje to jednak pomieszanie skryptu poprzez wysłanie 7 argumentów:

foo `date` joeuser@example.com

3
Jesteś wewnętrznie sprzeczny w pierwszym zdaniu. Pierwszy i drugi formularz nie zawsze będą wyświetlać to samo, co zademonstrujesz później.
jlliagre

Dzięki. Zmieniłem sformułowanie, aby było bardziej jasne.
Jim Stewart

3

W powłokach POSIX `date`jest starożytną formą zastępowania poleceń. Współczesna składnia to $(date).

W obu przypadkach są one rozszerzane do wyniku datez usuniętymi końcowymi znakami nowego wiersza (pod warunkiem, że wynik nie zawiera znaków NUL).

Jednakże, gdy nie znajduje się w podwójnym cudzysłowie i w kontekstach listy (na przykład w argumentach prostych poleceń, jak echow twoim przypadku), to rozwinięcie podlega ponadto:

  1. Dzielenie wyrazów : to znaczy „wynik datez usuniętymi końcowymi znakami nowej linii” jest dzielony zgodnie z bieżącą wartością $IFSzmiennej (domyślnie zawierającej spację, tabulator i znak nowej linii (i NUL z zsh)) na kilka słów .

    Na przykład, jeśli datewyjścia Fri 1 Nov 14:11:15 GMT 2013\n(jak to często robi w lokalizacji angielskiej i kontynentalnej w brytyjskiej strefie czasowej) i $IFSobecnie zawiera :, które zostaną podzielone na 3 słowach : Fri 1 Nov 14, 11i 15 GMT 2013.

  2. Nazwa pliku generacji (aka globbing ) (chyba zsh), to znaczy każde słowo wynikające z podziału powyżej jest szukali znaków wieloznacznych ( *, ?, [...]choć niektóre muszle mają więcej), a rozszerzony do listy nazw plików pasujących do tych wzorców. Na przykład, jeśli wyjście datejest ?%? 33 */*/* UVC 3432(jak to często jest w Wenus lokalizacjach i UVC strefy czasowej), i $IFSjest to wartość domyślna), to rozwija się do wszystkich nie-ukryty 3 nazwami znaków w bieżącym katalogu, którego środkowa postać jest %, 33, wszystkie nie ukryte pliki we wszystkich nie ukrytych podkatalogach wszystkich nie ukrytych podkatalogów bieżącego katalogu, UVCoraz 3432.

Dlatego:

  1. Powinieneś zawsze cytować (z podwójnymi cudzysłowami) podstawienia poleceń, chyba że chcesz, aby dzielenie słów lub generowanie nazw plików były wykonywane po ich rozwinięciu
  2. Jeśli chcesz dzielić słowa , powinieneś ustawić $IFSznaki, na które chcesz dzielić.
  3. Jeśli chcesz dzielić słowa, ale nie generować nazw plików , musisz wydać a, set +faby je wyłączyć.

Pojedyncze cytaty cytują wszystko, więc dosłownie należy traktować znaki z tyłu.

Przykład (użycie -xułatwia sprawdzenie, co się dzieje):

$ bash --norc -x
bash-4.2$ IFS=:
+ IFS=:
bash-4.2$ echo `date`
++ date
+ echo 'Fri  1 Nov 14' 42 '33 GMT 2013'
Fri  1 Nov 14 42 33 GMT 2013
bash-4.2$ echo "`date`"
++ date
+ echo 'Fri  1 Nov 14:42:41 GMT 2013'
Fri  1 Nov 14:42:41 GMT 2013

bash-4.2$ cd /lib/modules
+ cd /lib/modules
bash-4.2$ export TZ=UVC LC_ALL=vs_VS
+ export TZ=UVC LC_ALL=vs_VS
+ TZ=UVC
+ LC_ALL=vs_VS
bash-4.2$ unset -v IFS     # get the default behaviour
+ unset -v IFS
bash-4.2$ echo `date`
++ date
+ echo '?%?' 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
?%? 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
bash-4.2$ echo "`date`"
++ date
+ echo '?%? 33 */*/* UVC 3432'
?%? 33 */*/* UVC 3432

Jeśli dane wyjściowe zawierają znaki NUL, zachowanie różni się w zależności od powłoki: niektóre usuwają je, niektóre obcinają dane wyjściowe przy pierwszym znaku NUL, zshzachowują je, ale należy pamiętać, że w każdym razie polecenia zewnętrzne nie mogą przyjmować argumentów zawierających wartości NUL


Nie istnieje coś takiego jak „powłoka POSIX”. Istnieją powłoki, które mogą być zgodne z różnymi odpowiednimi standardami POSIX przy użyciu ograniczonego podzbioru ich funkcjonalności.
fpmurphy

0

Za pomocą `date` otrzymujesz wynik daty podzielony na wiele słów, ponieważ dzielenie słów odbywa się po zastąpieniu polecenia.

Za pomocą „data” otrzymujesz wynik daty jako jedno słowo / parametr, ponieważ pomiędzy podwójnymi cudzysłowami występuje polecenie, ale wynik nie jest dalej analizowany. To samo dotyczy rozszerzenia zmiennej, takiego jak „$ i” w moim przykładzie poniżej.

Z „data” dostajesz dosłowną „datę”, ponieważ nie ma podstawienia poleceń między pojedynczymi cudzysłowami.

Być może różnice między 3 postaciami będą bardziej widoczne w ten sposób:

> for i in `date`; do echo "$i"; done
Fr
1.
Nov
12:25:30
CET
2013

> for i in "`date`"; do echo "$i"; done
Fr 1. Nov 12:25:38 CET 2013

> for i in '`date`'; do echo "$i"; done
`date`
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.