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ę?

Jan
źródło

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 .

Chirag Bhatia - chirag64
źródło
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
Jim Stewart
źródło
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

Stéphane Chazelas
źródło
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`
Michael Suelmann
źródło