Jaka jest różnica między $ (stuff) a `stuff`?

265

Istnieją dwie składnie zastępowania poleceń: z nawiasami dolara i ze znakami wstecznymi. Działa top -p $(pidof init)i top -p `pidof init`daje tę samą moc wyjściową. Czy są to dwa sposoby robienia tego samego, czy też istnieją różnice?

tshepang
źródło
18
Zobacz także: BashFAQ / 082 .
Dennis Williamson
42
Przez chwilę myślałem, że to pytanie jQuery.
David Murdoch,
Wynik może zależeć od powłoki - niektóre obsługują oba.
artdanil

Odpowiedzi:

359

W starym stylu backquotes ` `traktują odwrotne ukośniki i zagnieżdżanie nieco inaczej. Nowy styl $()interpretuje wszystko pomiędzy ( )jako polecenie.

echo $(uname | $(echo cat))
Linux

echo `uname | `echo cat``
bash: command substitution: line 2: syntax error: unexpected end of file
echo cat

działa, jeśli zagnieżdżone cudzysłowy są zastępowane:

echo `uname | \`echo cat\``
Linux

zabawa z odwrotnym ukośnikiem:

echo $(echo '\\')
\\

echo `echo '\\'`
\

Nowy styl $()dotyczy wszystkich powłok zgodnych z POSIX .
Jak zauważył mouviciel , starsze style ` `mogą być konieczne dla starszych powłok.

Oprócz technicznego punktu widzenia stary styl ` `ma również wadę wizualną:

  • Trudno zauważyć: I like $(program) better than `program`
  • Łatwo pomylić z jednym cytatem: '`'`''`''`'`''`'
  • Nie tak łatwo pisać (może nawet nie na standardowym układzie klawiatury)

(i SE używa ` `do własnych celów, pisanie tej odpowiedzi było uciążliwe :)

machać
źródło
10
Jedyne, co chciałbym dodać, to to, że nazywam „(paren, a nie nawias klamrowy (czyli„ [”).
Kendall Helmstetter Gelner,
@Kendall: i tutaj myślałem, że „{” był lewą nawiasem przez te wszystkie lata ...
SamB
5
@Sam: { }jest zwykle nazywany „nawiasami klamrowymi” lub „nawiasami klamrowymi” en.wikipedia.org/wiki/Braces_(punctuation)#Braces
Jørn Schou-Rode
2
Odnoszę się również do „{” jako nawiasów klamrowych. Chociaż wydaje się to dziwne, musisz dodać kwalifikator „kędzierzawy”, jeśli nazywasz inne rzeczy nawiasami… Sądzę, że to tylko dlatego, że faktycznie się zawijają.
Kendall Helmstetter Gelner
1
@slim Nie wiem na klawiaturach w USA / Wielkiej Brytanii, ale na hiszpańskich klawiaturach `jest martwy klawisz, więc muszę wpisać dwukrotne kliknięcie (coś, o czym zwykle zapominam, że nawet potrafię) lub cofnięcie, a następnie spację, która jest ból.
Darkhogg
41

Oczywistą różnicą, którą obserwuję, jest to, że nie można zagnieżdżać tyknięć podczas gdy można zagnieżdżać $(). Być może oba istnieją ze starszych powodów. Podobnie polecenia .i sourcesą synonimami.

balki
źródło
10
Niektóre pociski pochodzące od Bourne'a nie rozpoznają source. Dash jest jednym z przykładów.
Dennis Williamson
14
To nieprawda. Możesz zagnieździć backstick na dowolnym poziomie, po prostu bardziej boleśnie. Zauważ, że oba $(...)i `...`są standardowe (te ostatnie są przestarzałe), podczas gdy .są standardowe, ale niesource
Stéphane Chazelas
3
Korekta, tylko (t)cshnie można ich zagnieżdżać. (t)cshnie obsługują $(...)jednak. Jednak obsługują source(i nie .).
Stéphane Chazelas
28

$()nie działa ze starą powłoką Bourne'a. Ale minęły lata, odkąd pracowałem ze starą skorupą Bourne'a.

mouviciel
źródło
Stary jak w latach siedemdziesiątych i wczesnych osiemdziesiątych, prawda?
Christopher
6

Kolejna uwaga, $()zużyje więcej zasobów systemowych niż backticks, ale jest nieco szybsza.

W opanowaniu skryptów powłoki Unixa Randal K. Michael wykonał test w rozdziale o nazwie „24 sposoby przetwarzania pliku linia po linii”.

Cuonglm
źródło
2
To twierdzenie jest nonsensowne. Nie ma powodu, dla którego powinien być szybszy, ponieważ po prostu używa innej notacji dla analizatora składni.
schily
@schily: Może, cytuję tylko z książki, możesz ją przeczytać, aby uzyskać więcej szczegółów.
cuonglm
3
Zwykle zgadzam się z @schily ... dlaczego to zabiera więcej zasobów?
Wildcard,
2
@Wildcard, przypuszczam, że to dlatego, $()że twój skrypt jest o jeden bajt większy niż gdyby był używany `(zakładając, że nie zagnieżdżasz ich i nie używasz odwrotnych ukośników). Co do tego, który byłby szybszy do przeanalizowania, byłby różny dla różnych powłok i byłby nieistotny jako nieistotny w porównaniu z kosztem utworzenia potoku i rozwidlenia procesu, który pociąga za sobą zastąpienie polecenia.
Stéphane Chazelas,
5

Aby dodać do tego, co powiedzieli tutaj inni, możesz użyć tylnych klawiszy, aby zasymulować wbudowane komentarze:

echo foo `# I'm a comment!` bar

Wyjście jest: foo bar.

Aby uzyskać więcej informacji, zobacz następujące informacje: https://stackoverflow.com/a/12797512 (zwróć uwagę również na komentarze poniżej tego postu)

phk
źródło
1

$()Składnia nie będzie działać ze starym Bourne Shell.
Z nowszymi powłokami ` `i $()są równoważne, ale $()jest o wiele wygodniejszy w użyciu, gdy trzeba zagnieżdżać wiele poleceń.

Na przykład :

echo $(basename $(dirname $(dirname /var/adm/sw/save )))

łatwiej jest pisać i debugować niż:

echo `basename \`dirname \\\`dirname /var/adm/sw/save \\\`\``
Emmanuel
źródło
1
Chociaż $ () może wyglądać ładnie, jest to kłopotliwe przy implementacji powiązanego parsera, ponieważ wymaga podwójnego rekurencyjnego parsera.
schily
6
@schily Z drugiej strony, co byłoby powłoką bez dobrego parsera.
Emmanuel,
1
Problem polega na tym, że musisz wiedzieć, gdzie kończy się łańcuch przed wywołaniem parsera. Jest to stosunkowo proste z backtickami, ale jest trudne z nawiasami, ponieważ są one używane do różnych celów w powłoce. Potrzebujesz więc parsera dwa razy w sposób, który nie istnieje w powłoce Bourne'a.
schily