Sono necessarie le virgolette per l'assegnazione delle variabili locali?


36

Posso omettere in modo sicuro le virgolette sul lato destro di un incarico locale?

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

Sono principalmente interessato bash, ma qualsiasi informazione sui casi d'angolo in altre shell è benvenuta.


Penso che non faccia alcuna differenza se si trova su una riga come se l'avessi nella tua funzione. Le assegnazioni non richiedono preventivi. Vedi mpi-sb.mpg.de/departments/rg1/teaching/unixffb-ss98/…
jirib

Risposte:


41

Le quotazioni sono necessari export foo="$var"o local foo="$var"(o readonly, typeset, declareed altre variabili che dichiara comandi ) in:

  • dash
  • il shdi NetBSD (basato anche sulla shell Almquist).
  • Il shdi FreeBSD 9.2 o precedente (vedi la modifica in 9.3 )
  • yash
  • zshcon versioni precedenti alla 5.1 in ksho shemulazione (o per export var="$(cmd)"dove zshaltrimenti si comporterebbe la suddivisione delle parole (non globbing)).

Altrimenti l'espansione variabile sarebbe soggetta alla suddivisione delle parole e / o alla generazione di nomi di file come in qualsiasi argomento di qualsiasi altro comando.

E non sono necessari in:

  • bash
  • ksh (tutte le implementazioni)
  • il shdi FreeBSD 9.3 o più recente
  • busybox 'a base di cenere sh(dal 2005)
  • zsh

In zsh, split + glob non viene mai eseguito al momento dell'espansione dei parametri, a meno che in sho kshemulazione, ma split (non glob) viene eseguito in sostituzione del comando. Dalla versione 5.1, export/ locale altri comandi di dichiarazione sono diventati comandi a doppia parola chiave / incorporati come nelle altre shell precedenti, il che significa che il quoting non è necessario, anche in sh/ kshemulazione e persino per la sostituzione dei comandi.

Ci sono casi speciali in cui è necessario un preventivo anche in quelle shell, come:

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

O più in generale, se viene citato qualcosa a sinistra del =(incluso il =) o il risultato di una certa espansione (come export 'foo'="$var", export foo\="$var"o export foo$((n+=1))="$var"(che $((...))dovrebbe anche essere citato effettivamente) ...). O in altre parole quando l'argomento exportnon sarebbe un'assegnazione variabile valida se scritto senza il export.

Se il export/ localnome del comando stesso è citato (anche solo in parte, come "export" a="$b", 'ex'port a="$b", \export a="$b", o anche ""export a="$b"), le virgolette $bsono necessarie tranne in AT & T kshe mksh.

Se export/ localo parte di esso è il risultato di qualche espansione (come in cmd=export; "$cmd" a="$b"o anche export$(:) a="$b") o in cose simili dryrun=; $dryrun export a="$b"), allora le virgolette sono necessarie in ogni shell.

Nel caso di > /dev/null export a="$b", le quotazioni sono necessarie in pdkshe alcuni dei suoi derivati.

Per command export a="$b", le virgolette sono necessarie in ogni shell ma mkshe ksh93(con gli stessi avvertimenti circa commande exportnon essere il risultato di una certa espansione).

Non sono necessari in nessuna shell quando sono scritti:

foo=$var export foo

(tale sintassi è anche compatibile con la shell Bourne ma nelle versioni recenti di zsh, funziona solo quando è in sh/ kshemulazione).

(nota che var=value local varnon dovrebbe essere usato poiché il comportamento varia tra le shell).

Si noti inoltre che l'utilizzo exportcon un'assegnazione significa anche che lo stato di uscita di cmdin export var="$(cmd)"viene perso. Farlo perché export var; var=$(cmd)non ha questo problema.

Fai attenzione anche a questo caso speciale con bash:

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

Il mio consiglio sarebbe di citare sempre.


3
Si noti che tra zshvirgolette è necessario local foo="$(cmd)"perché il wordplitting (ma non la generazione del nome file) viene eseguito per sostituzioni di comandi non quotate (ma non per espansioni di parametri non quotate), a meno che non KSH_TYPESETsia abilitato, nel qual caso le virgolette non sono necessarie. Ha senso? No? Quindi cita sempre tutto a meno che tu non sappia esattamente cosa stai facendo.
Matt,

2
@Matt, adoro le tue conclusioni. : D È divertente, la maggior parte di ciò che ho imparato sugli script di shell proviene da questo scambio di stack, quindi non ho realizzato che citare sempre le tue variabili non è una conoscenza comune tra gli autori di script. Sto scoprendo che ho molto da sistemare per fare degli script di produzione esistenti scritti da persone che non hanno citato e non sapevano esattamente cosa stavano facendo ....
Wildcard,

3

In genere cito qualsiasi utilizzo di variabili in cui potrebbero esserci caratteri come spazi bianchi. Altrimenti incontrerai problemi come questo:

#!/bin/bash

bar="hi bye"

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

foo

L'uso della variabile in un compito non sembra aver bisogno delle virgolette, ma quando vai a usarlo come nel caso printfti servirà tra virgolette lì:

  printf "%s\n" "$myvar"

NOTA: Ricorda che la variabile $IFSè ciò che regola i caratteri di separazione.

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>''.

Esempio

Con il debug abilitato in Bash possiamo vedere cosa sta succedendo dietro le quinte.

$ 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

In quanto sopra possiamo vedere che la variabile, è $barstata tramandata bene $myvarma poi quando siamo andati a usare $myvardovevamo essere a conoscenza del contenuto di $myvarquando siamo andati a usarla.


2
la suddivisione delle parole non è l'unico problema con le variabili non quotate, devi considerare anche la generazione del nome del file (aka globbing) (anche se (entrambi) non si applica nelle assegnazioni di variabili e per bashe kshin local/ typeset... builtin speciali).
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.