Czy do przypisania zmiennych lokalnych potrzebne są oferty?

36

Czy mogę bezpiecznie pominąć cytaty po prawej stronie zadania lokalnego?

function foo {
    local myvar=${bar}
    stuff()
}

Interesuje mnie głównie bash, ale mile widziane są wszelkie informacje na temat narożnych skrzynek w innych powłokach.

rahmu
źródło
Myślę, że nie ma znaczenia, czy jest w jednej linii, tak jak masz to w swojej funkcji. Zadania nie wymagają cytowania. Zobacz mpi-sb.mpg.de/departments/rg1/teaching/unixffb-ss98/…
jirib,

Odpowiedzi:

41

Cytaty są potrzebne export foo="$var"lub local foo="$var"(i readonly, typeset, declarea pozostałe zmienne deklarowania poleceń ) z:

  • dash
  • shNetBSD (również w oparciu o Almquist Shell).
  • Wersja shFreeBSD 9.2 lub starsza (patrz zmiana w 9.3 )
  • yash
  • zshz wersjami wcześniejszymi niż 5.1 kshlub shemulującymi (lub dla export var="$(cmd)"których w zshinnym przypadku wykonywałby dzielenie słów (bez globowania)).

W przeciwnym razie interpretacja zmiennych podlegałaby podziałowi słów i / lub generowaniu nazw plików, jak w każdym argumencie do dowolnego innego polecenia.

I nie są potrzebne w:

  • bash
  • ksh (wszystkie wdrożenia)
  • shFreeBSD 9.3 lub nowszej
  • busybox na bazie popiołu sh(od 2005)
  • zsh

W zsh, split + glob nigdy nie jest wykonywane po rozszerzeniu parametru, chyba że w shlub kshemulacji, ale split (nie glob) jest wykonywany po zastąpieniu polecenia. Od wersji 5.1, export/ locali inne polecenia deklaracji stały podwójny kluczowe / wbudowane komendy jak w innych skorup powyżej, co oznacza, cytując nie jest konieczne, nawet w sh/ kshemulacji, a nawet do zastąpienia poleceń.

Istnieją specjalne przypadki, w których cytowanie jest potrzebne nawet w tych powłokach, jak na przykład:

a="b=some value"
export "$a"

Lub bardziej ogólnie, jeśli cokolwiek zostało z =(w tym =) jest cytowane lub jest wynikiem jakiegoś rozszerzenia (jak export 'foo'="$var", export foo\="$var"lub export foo$((n+=1))="$var"(które $((...))powinno być faktycznie cytowane) ...). Innymi słowy, gdy argument argumentu exportnie byłby prawidłowym przypisaniem zmiennej, gdyby został napisany bez export.

Jeśli export/ localsama nazwa polecenia jest cytowany (nawet w części, takich jak "export" a="$b", 'ex'port a="$b", \export a="$b", lub nawet ""export a="$b"), cytaty wokół $bpotrzebne są wyjątkiem AT & T kshi mksh.

Jeśli export/ locallub jakaś jego część jest wynikiem jakiegoś rozszerzenia (jak w cmd=export; "$cmd" a="$b"lub nawet export$(:) a="$b") lub w rzeczach takich jak dryrun=; $dryrun export a="$b"), wówczas cudzysłowy są potrzebne w każdej powłoce.

W przypadku > /dev/null export a="$b", potrzebne są notowania pdkshi niektóre z jego pochodnych.

Ponieważ command export a="$b"cytaty są potrzebne w każdej powłoce, ale mkshi ksh93(z tymi samymi zastrzeżeniami commandi exportnie będącymi wynikiem niektórych rozszerzeń).

Po napisaniu nie są potrzebne w żadnej powłoce:

foo=$var export foo

(ta składnia jest również kompatybilna z powłoką Bourne'a, ale w najnowszych wersjach zshdziała tylko w trybie sh/ kshemulacji).

(należy pamiętać, że var=value local varnie należy tego używać, ponieważ zachowanie różni się w zależności od powłoki).

Należy również pamiętać, że używanie exportz przypisaniem oznacza również utratę statusu wyjścia dla cmdin export var="$(cmd)". Robienie tego, ponieważ export var; var=$(cmd)nie ma tego problemu.

Uważaj również na ten specjalny przypadek z bash:

$ bash -c 'IFS=; export a="$*"; echo "$a"' bash a b
ab
$ bash -c 'IFS=; export a=$*; echo "$a"' bash a b
a b

Radzę zawsze cytować.

Stéphane Chazelas
źródło
3
Zauważ, że w zshcudzysłowach potrzebne, local foo="$(cmd)"ponieważ dzielenie słów (ale nie generowanie nazw plików) jest wykonywane dla niecytowanych podstawień poleceń (ale nie dla niecytowanych rozszerzeń parametrów), chyba że KSH_TYPESETjest włączone, w którym to przypadku cudzysłowy nie są potrzebne. Ma sens? Nie? Następnie zawsze cytuj wszystko, chyba że wiesz dokładnie, co robisz.
Mat.
2
@Matt, uwielbiam twój wniosek. : D To zabawne, większość tego, czego nauczyłem się o skryptach powłoki, pochodzi z tej wymiany stosów, więc nie zdawałem sobie sprawy, że zawsze cytowanie zmiennych nie jest powszechną wiedzą wśród autorów skryptów. Zauważyłem, że mam wiele do zrobienia w istniejących skryptach produkcyjnych napisanych przez ludzi, którzy nie cytowali i nie wiedzieli dokładnie, co robią ...
Wildcard
3

Zazwyczaj cytuję użycie zmiennych, w których mogą występować znaki, takie jak białe znaki. W przeciwnym razie wystąpią takie problemy:

#!/bin/bash

bar="hi bye"

function foo {
  local myvar=${bar}
  printf "%s\n" $myvar
  printf "%s\n" "$myvar"
}

foo

Użycie zmiennej w przydziale nie wydaje się wymagać cudzysłowów, ale kiedy idziesz do jej użycia, tak jak w printftekście, musisz ją tam zacytować:

  printf "%s\n" "$myvar"

UWAGA: Pamiętaj, że zmienna $IFSdecyduje o tym, jakie są znaki separatora.

IFS    The  Internal  Field  Separator that is used for word splitting after 
       expansion and to split lines into words with the read builtin command. 
       The default value is ``<space><tab><newline>''.

Przykład

Po włączeniu debugowania w Bash możemy zobaczyć, co dzieje się za kulisami.

$ bash -x cmd.bash 
+ bar='hi bye'
+ foo
+ local 'myvar=hi bye'
+ printf '%s\n' hi bye
hi
bye
+ printf '%s\n' 'hi bye'
hi bye

Powyżej widać, że zmienna $barzostała dobrze przekazana, $myvarale kiedy poszliśmy z niej korzystać $myvar, musieliśmy być poznawcami zawartości, $myvarkiedy z niej skorzystaliśmy.

slm
źródło
2
Słowo dzielenie nie jest to jedyny problem ze zmiennymi nienotowanych, trzeba wziąć pod uwagę generacja nazwa pliku (aka globbing), a także (choć że (oba) nie ma zastosowania w zmiennych zadań oraz bashoraz kshw local/ typeset... Specjalne builtins).
Stéphane Chazelas