Apakah kutipan diperlukan untuk penugasan variabel lokal?


36

Bisakah saya dengan aman menghilangkan tanda kutip di sisi kanan tugas lokal?

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

Saya terutama tertarik bash, tetapi setiap info tentang kasus sudut di kulit lain dipersilakan.


Saya pikir tidak ada bedanya jika itu ada di satu baris seperti yang Anda miliki di fungsi Anda. Tugas tidak perlu mengutip. Lihat mpi-sb.mpg.de/departments/rg1/teaching/unixffb-ss98/…
jirib

Jawaban:


41

Kutipan diperlukan dalam export foo="$var"atau local foo="$var"(atau readonly, typeset, declaredan variabel menyatakan lainnya perintah ) di:

  • dash
  • yang shdari NetBSD (juga didasarkan pada Almquist shell).
  • The shFreeBSD 9.2 atau lebih tua (lihat perubahan di 9.3 )
  • yash
  • zshdengan versi sebelum 5.1 dalam kshatau shemulasi (atau di export var="$(cmd)"mana zshakan melakukan pemisahan kata sebaliknya (tidak menggumpal)).

Seperti sebaliknya, ekspansi variabel akan dikenakan pemisahan kata dan / atau pembuatan nama file seperti dalam argumen apa pun terhadap perintah lain.

Dan tidak diperlukan di:

  • bash
  • ksh (semua implementasi)
  • yang shdari FreeBSD 9.3 atau yang lebih baru
  • busybox 'berbasis abu sh(sejak 2005)
  • zsh

In zsh, split + glob tidak pernah dilakukan pada ekspansi parameter, kecuali dalam shatau kshemulasi, tetapi split (bukan glob) dilakukan pada substitusi perintah. Sejak versi 5.1, export/ localdan perintah deklarasi lainnya telah menjadi kata kunci ganda / perintah builtin seperti pada shell lain di atas, yang berarti mengutip tidak diperlukan, bahkan dalam sh/ kshemulasi dan bahkan untuk substitusi perintah.

Ada kasus-kasus khusus di mana mengutip diperlukan bahkan dalam cangkang tersebut seperti:

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

Atau lebih umum, jika sesuatu yang tersisa dari =(termasuk =) dikutip atau hasil dari ekspansi (seperti export 'foo'="$var", export foo\="$var"atau export foo$((n+=1))="$var"(yang $((...))juga harus dikutip sebenarnya) ...). Atau dengan kata lain ketika argumen untuk exporttidak akan menjadi tugas variabel yang valid jika ditulis tanpa export.

Jika export/ localnama perintah itu sendiri dikutip (bahkan di bagian seperti "export" a="$b", 'ex'port a="$b", \export a="$b", atau bahkan ""export a="$b"), tanda kutip sekitar $bdiperlukan kecuali pada AT & T kshdan mksh.

Jika export/ localatau sebagian dari itu adalah hasil dari ekspansi (seperti dalam cmd=export; "$cmd" a="$b"atau bahkan export$(:) a="$b") atau dalam hal-hal seperti dryrun=; $dryrun export a="$b"), maka tanda kutip diperlukan di setiap shell.

Dalam hal > /dev/null export a="$b", kuotasi diperlukan dalam pdkshdan beberapa turunannya.

Karena command export a="$b", tanda kutip diperlukan di setiap shell tetapi mkshdan ksh93(dengan peringatan yang sama tentang commanddan exporttidak menjadi hasil dari ekspansi).

Mereka tidak diperlukan dalam shell apa pun ketika ditulis:

foo=$var export foo

(Sintaks itu juga kompatibel dengan shell Bourne tetapi dalam versi terbaru zsh, hanya berfungsi ketika di sh/ kshemulasi).

(perhatikan bahwa var=value local vartidak boleh digunakan karena perilaku bervariasi di seluruh cangkang).

Perhatikan juga bahwa menggunakan exportdengan penugasan juga berarti bahwa status keluar cmdmasuk export var="$(cmd)"hilang. Melakukannya karena export var; var=$(cmd)tidak memiliki masalah itu.

Waspadalah terhadap kasus khusus ini dengan bash:

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

Saran saya adalah selalu mengutip.


3
Perhatikan bahwa dalam zshtanda kutip yang dibutuhkan untuk local foo="$(cmd)"karena wordsplitting (tapi tidak nama file generasi) yang dilakukan untuk substitusi perintah kuotasi (tetapi tidak untuk ekspansi parameter kuotasi), kecuali KSH_TYPESETdiaktifkan, di mana kutipan kasus tidak diperlukan. Masuk akal? Tidak? Maka selalu kutip semuanya kecuali Anda tahu persis apa yang Anda lakukan.
Matt

2
@ Mat, saya suka kesimpulan Anda. : D Ini yang lucu, sebagian besar dari apa yang telah saya pelajari dari shell scripting berasal dari stackexchange ini, sehingga saya tidak menyadari bahwa selalu mengutip variabel Anda adalah tidak pengetahuan umum di antara penulis naskah. Saya menemukan saya memiliki banyak perbaikan untuk melakukan skrip produksi yang ada yang ditulis oleh orang-orang yang tidak mengutip, dan tidak tahu persis apa yang mereka lakukan ....
Wildcard

3

Saya biasanya mengutip setiap penggunaan variabel di mana mungkin ada karakter seperti spasi putih. Kalau tidak, Anda akan mengalami masalah seperti ini:

#!/bin/bash

bar="hi bye"

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

foo

Penggunaan variabel dalam suatu tugas tampaknya tidak membutuhkan tanda kutip, tetapi ketika Anda menggunakannya, printfAnda akan membutuhkannya yang dikutip di sana:

  printf "%s\n" "$myvar"

CATATAN: Ingat bahwa variabel $IFSadalah apa yang mengatur apa karakter pemisah.

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

Contoh

Dengan debugging diaktifkan di Bash kita dapat melihat apa yang terjadi di balik layar.

$ 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

Dalam contoh di atas kita dapat melihat bahwa variabel, $bardibagikan dengan baik ke $myvartetapi kemudian ketika kita pergi untuk menggunakan $myvarkita harus menyadari isi $myvarketika kita pergi untuk menggunakannya.


2
pemisahan kata bukan satu-satunya masalah dengan variabel yang tidak dikutip, Anda harus mempertimbangkan pembuatan nama file (alias globbing) juga (meskipun itu (keduanya) tidak berlaku dalam tugas variabel dan untuk bashdan kshdi local/ typeset... builtin khusus).
Stéphane Chazelas
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.