Là trích dẫn cần thiết cho việc gán biến cục bộ?


36

Tôi có thể bỏ qua các trích dẫn ở bên phải của bài tập địa phương không?

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

Tôi chủ yếu quan tâm đến bash, nhưng bất kỳ thông tin nào về các trường hợp góc trong các vỏ khác đều được chào đón.


Tôi nghĩ rằng nó không có gì khác biệt nếu nó nằm trên một dòng giống như bạn có nó trong chức năng của bạn. Bài tập không cần trích dẫn. Xem mpi-sb.mpg.de/depeces/rg1/teaching/unixffb-ss98/ trộm
jirib

Câu trả lời:


41

Dấu ngoặc kép là cần thiết trong export foo="$var"hoặc local foo="$var"(hoặc readonly, typeset, declarevà biến tuyên bố khác lệnh ) trong:

  • dash
  • các shcủa NetBSD (cũng dựa trên vỏ Almquist).
  • Các shcủa FreeBSD 9.2 trở lên (xem sự thay đổi trong 9,3 )
  • yash
  • zshvới các phiên bản trước 5.1 trong kshhoặc shmô phỏng (hoặc cho export var="$(cmd)"nơi zshsẽ thực hiện phân tách từ nếu không (không phải là toàn cầu)).

Nếu không, việc mở rộng biến sẽ chịu sự phân tách từ và / hoặc tạo tên tệp như trong bất kỳ đối số nào đối với bất kỳ lệnh nào khác.

Và không cần thiết trong:

  • bash
  • ksh (tất cả các triển khai)
  • các shcủa FreeBSD 9,3 hoặc mới hơn
  • busybox 'dựa trên tro sh(từ năm 2005)
  • zsh

Trong zsh, split + global không bao giờ được thực hiện khi mở rộng tham số, trừ khi trong shhoặc kshmô phỏng, nhưng tách (không phải toàn cầu) được thực hiện khi thay thế lệnh. Vì phiên bản 5.1, export/ localvà các lệnh khai báo khác đã trở thành các lệnh từ khóa / dựng sẵn kép như trong các shell khác ở trên, điều đó có nghĩa là trích dẫn là không cần thiết, ngay cả trong sh/ kshmô phỏng và thậm chí để thay thế lệnh.

Có những trường hợp đặc biệt khi trích dẫn là cần thiết ngay cả trong các shell đó như:

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

Hay nói chung hơn, nếu bất cứ điều gì còn lại của =(bao gồm =) được trích dẫn hoặc kết quả của một số mở rộng (như export 'foo'="$var", export foo\="$var"hoặc export foo$((n+=1))="$var"( $((...))cũng nên được trích dẫn thực sự) ...). Hay nói cách khác, khi đối số exportsẽ không phải là một phép gán biến hợp lệ nếu được viết mà không có export.

Nếu export/ localtên lệnh bản thân được trích dẫn (ngay cả trong phần như "export" a="$b", 'ex'port a="$b", \export a="$b", hoặc thậm chí ""export a="$b"), các dấu ngoặc kép quanh $blà cần thiết trừ AT & T kshmksh.

Nếu export/ localhoặc một phần nào đó là kết quả của một số mở rộng (như trong cmd=export; "$cmd" a="$b"hoặc thậm chí export$(:) a="$b") hoặc trong những thứ như dryrun=; $dryrun export a="$b"), thì dấu ngoặc kép là cần thiết trong mỗi vỏ.

Trong trường hợp > /dev/null export a="$b", các trích dẫn là cần thiết trong pdkshvà một số dẫn xuất của nó.

Đối với command export a="$b", các trích dẫn là cần thiết trong mọi shell nhưng mkshksh93(với cùng một cảnh báo về commandexportkhông phải là kết quả của một số mở rộng).

Chúng không cần thiết trong bất kỳ shell nào khi được viết:

foo=$var export foo

(cú pháp đó cũng tương thích với trình bao Bourne nhưng trong các phiên bản gần đây của zsh, chỉ hoạt động khi trong sh/ kshmô phỏng).

(lưu ý rằng var=value local varkhông nên được sử dụng vì hành vi khác nhau giữa các vỏ).

Cũng lưu ý rằng việc sử dụng exportvới một bài tập cũng có nghĩa là trạng thái thoát của cmdin export var="$(cmd)"bị mất. Làm điều đó như export var; var=$(cmd)không có vấn đề đó.

Cũng hãy cẩn thận với trường hợp đặc biệt này với bash:

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

Lời khuyên của tôi sẽ là luôn luôn trích dẫn.


3
Lưu ý rằng trong zshdấu ngoặc kép cần thiết local foo="$(cmd)"vì từ viết (nhưng không tạo tên tệp) được thực hiện cho các thay thế lệnh không được trích dẫn (nhưng không phải cho mở rộng tham số không trích dẫn), trừ khi KSH_TYPESETđược bật, trong trường hợp đó trích dẫn không cần thiết. Có lý? Không? Sau đó, luôn luôn trích dẫn mọi thứ trừ khi bạn biết chính xác những gì bạn đang làm.
Matt

2
@Matt, tôi thích kết luận của bạn. : D Thật buồn cười, hầu hết những gì tôi học được về kịch bản shell đều đến từ stackexchange này, do đó tôi không nhận ra rằng luôn trích dẫn các biến của bạn không phải là kiến thức phổ biến giữa các tác giả kịch bản. Tôi đang tìm thấy tôi có rất nhiều cách khắc phục để thực hiện các kịch bản sản xuất hiện có được viết bởi những người không trích dẫn và không biết chính xác những gì họ đang làm ....
Wildcard

3

Tôi thường trích dẫn bất kỳ việc sử dụng các biến trong đó có thể có các ký tự như khoảng trắng. Nếu không, bạn sẽ gặp vấn đề như thế này:

#!/bin/bash

bar="hi bye"

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

foo

Việc sử dụng biến trong một bài tập dường như không cần dấu ngoặc kép, nhưng khi bạn sử dụng nó, chẳng hạn như trong phần printfbạn sẽ cần nó được trích dẫn ở đó:

  printf "%s\n" "$myvar"

LƯU Ý: Hãy nhớ rằng biến $IFSlà thứ chi phối các ký tự phân cách.

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

Thí dụ

Với tính năng gỡ lỗi được kích hoạt trong Bash, chúng ta có thể thấy những gì xảy ra đằng sau hậu trường.

$ 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

Ở trên chúng ta có thể thấy rằng biến số $barđã được xử lý tốt $myvarnhưng sau đó khi chúng ta sử dụng, $myvarchúng ta phải nhận thức được nội dung $myvarkhi chúng ta sử dụng nó.


2
từ tách không phải là vấn đề duy nhất với các biến thể viện chứng, bạn phải xem xét thế hệ tên tập tin (aka globbing) cũng (mặc dù đó (cả hai) không áp dụng trong các bài tập biến và cho bashkshtrong local/ typeset... builtins đặc biệt).
Stéphane Chazelas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.