Lỗi có thể xảy ra trong Bash?: Foo () {echo Hồi $ {var [0]} W; }; var = (thanh baz) foo


22

HĐH : Ubuntu 16.04.3

Vỏ : Bash 4.3.48


Tôi biết rằng có thể tạm thời thay đổi nội dung của một biến như trong var=value command, có lẽ IFS= read -r varlà trường hợp đáng chú ý nhất của điều này.

Và, nhờ wiki của Greg , tôi cũng hiểu:

# Why this
foo() { echo "$var"; }
var=value foo

# And this does work
var=value; echo "$var"

# But this doesn't
var=value echo "$var"

Điều thoát khỏi sự hiểu biết của tôi là thế này:

$ foo() { echo "${var[0]}"; }
$ var=(bar baz) foo
(bar baz)

Theo như tôi biết (và theo logic của các ví dụ trước), thì nó nên in barchứ không phải (bar baz).

Điều này chỉ xảy ra với tôi? Đây có phải là hành vi dự định và tôi đang thiếu một cái gì đó? Hay đây là một lỗi?


3
Có lẽ nó có liên quan đến thực tế là bash không hỗ trợ mảng như các biến môi trường?
Jesse_b

3
@Jlie_b Có thể. Mặc dù khi tôi chạy export var=(foo bar); echo "${var[0]}"nó in foo, không (foo bar).
nxnev

1
Odd, điều đó làm việc cho tôi là tốt. Và sử dụng exportnó cho thấy:declare -ax var=([0]="foo" [1]="bar")
Jesse_b

3
Môi trường không thể chứa mảng, AFAIK. Ví dụ, export i_am_array=(foo bar); /usr/bin/env | grep i_am_arraykhông có đầu ra ở đây.
derobert

3
Ngoài ra: foo() { declare -p var; } ; var=(bar baz) foocung cấp declare -x var="(bar baz)"xác nhận nó được coi là một chuỗi, không phải là một mảng
derobert

Câu trả lời:


19

Nói chung gọi:

var=value cmd

nơi mà cmdmột chức năng không phải là di động.

Với bash, nó chỉ hoạt động cho các biến vô hướng (và được x=(...)phân tích thành một mảng nhưng được gán là vô hướng) và có một số vấn đề với phạm vi nếu bạn làm điều đó, với ksh93yash, nó hoạt động nhưng định nghĩa biến vẫn còn sau đó. Với mksh, bạn nhận được một lỗi cú pháp. Trong shell Bourne, nó hoàn toàn không hoạt động, ngay cả đối với các biến vô hướng.

Cũng lưu ý rằng ngay cả với các biến vô hướng, liệu biến đó có được xuất trong hàm hay không (nghĩa là được truyền cho các lệnh đang được thực thi) thay đổi từ shell sang shell (nó nằm trong bash, yash, mksh, zsh, nhưng không phải trong ksh, tro).

Nó chỉ hoạt động theo cách bạn mong đợi zsh. Lưu ý rằng zshcác chỉ số mảng bắt đầu từ 1.

bash-4.4$ zsh
$ a=(before value)
$ f() echo $a[1]
$ a=(temp value) f
temp
$ echo $a[1]
before

12

Đây không chỉ là một lỗi, nó dường như là một tính năng chưa được thực hiện mà không có kế hoạch nào là như vậy. Danh sách gửi thư này từ năm 2014 có cái này từ người tạo:

May mắn thay, trong bash 4.3 (patchlevel 25), bạn không thể chỉ -DARRAY_EXPORT và nhận nhập / xuất biến mảng. Mã không biên dịch và nếu bạn sửa nó, nó không liên kết và nếu bạn sửa nó, tốt, bạn sẽ gặp vấn đề sau.

Đó là một tấn rắc rối phải trải qua chỉ vì điều này. Tôi không có bất kỳ kế hoạch nào để cho phép xuất mảng.

Lấy từ repo git mới nhất cho Bash có điều này trong variables.c:

  #  if ARRAY_EXPORT
        /* Array variables may not yet be exported. */

Đề nghị rằng bất cứ điều gì là không hoàn thành.


5
Ở đây, đây là một chức năng, vì vậy không có câu hỏi nào về việc xuất bất cứ thứ gì vì không có execve()cuộc gọi hệ thống nào được tham gia. Xem zshshell để hỗ trợ các chức năng gọi với một mảng tạm thời được đặt theo cách đó.
Stéphane Chazelas

@ StéphaneChazelas Nhưng môi trường thay đổi (bằng cách thêm một biến mới) và sau đó hoàn nguyên trở lại, sau khi chức năng hoàn thành (tôi nói về trường hợp này my_var=one func_bar:). Chúng ta có thể nói, đó exportlà thêm vào môi trường và do đó, xuất khẩu được sử dụng ở đây, dưới mui xe? Nhìn vào câu trả lời của tôi, tôi đã thêm mã trình diễn.
MiniMax

10

Từ man bashphần BUGS (phiên bản của bash4.3):

GIỎI

   Array variables may not (yet) be exported.

Mã tiếp theo chứng minh rằng một biến tạm thời tồn tại trong môi trường, chỉ khi hàm đang chạy. Khi chức năng hoàn thành, biến tạm thời biến mất.

### defining the "bar" function
### it pass all environment variables to the "grep" command
### and the "grep" prints the only "my_var" variable from it
bar() { env | grep my_var=; }

### calls the "bar" function with the temporary 
### variable "my_var" created and assigned.
my_var=one bar

my_var=one         ### The output. The environment contains the "my_var" variable

### checks, does the environment still have the "my_var" variable
### (It doesn't have.)
env | grep my_var=
                   ### The output is empty,
                   ### the environment doesn't contain the "my_var" variable

Thông tin liên quan:

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.