Hành vi bất ngờ ở Bash


7

Từ man bash:

A simple command is a sequence of optional variable assignments
followed by blank-separated words and redirections, and
terminated by a control operator. The first word specifies the
command to be executed, and is passed as argument zero. The
remaining words are passed as arguments to the invoked command.

Vì vậy, nó hoàn toàn hợp pháp để viết:

foo=bar echo $foo

nhưng nó không hoạt động như tôi mong đợi (nó chỉ in một dòng mới). Nó khá lạ đối với tôi kể từ:

$ foo=bar printenv
foo=bar
TERM=rxvt-unicode
[...]

Ai đó có thể vui lòng giải thích cho tôi nơi tôi đang làm sai?

Câu trả lời:


6

Điều này xảy ra vì việc mở rộng biến được thực hiện trước khi lệnh được chạy. Tại thời điểm mở rộng biến số xảy ra, foo không được đặt, vì vậy nó mở rộng thành chuỗi rỗng. Lệnh sau đó chạy, thiết lập foo.


1
Ngoài ra, lưu ý rằng vì foo được đặt làm tiền tố cho lệnh echo, nên nó chỉ được đặt cho lệnh đó (chứ không phải cho các lệnh tiếp theo). So sánh với foo=bar eval 'echo eval sees $foo'; echo echo sees $foo (ở đây, kể từ khi $foo được mở rộng trong eval lệnh, giá trị sẽ được thay thế ở đó, nhưng không phải cho lệnh echo tiếp theo).
Gordon Davisson

1
Đây là một nhiệm vụ trong môi trường của trẻ em (tức là echo trong câu hỏi ban đầu hoặc eval trong ví dụ của Gordon). Bài tập thay đổi trong môi trường của trẻ không ảnh hưởng đến các giá trị biến trong cha mẹ. foo=bar eval 'foo=$foo'; echo $foo chỉ xuất ra một dòng mới.
Dennis Williamson

Từ man bash: "Nếu không có kết quả tên lệnh, các phép gán biến ảnh hưởng đến môi trường shell hiện tại. Mặt khác, các biến được thêm vào môi trường của lệnh đã thực hiện và không ảnh hưởng đến môi trường shell hiện tại. Nếu bất kỳ phép gán nào cố gắng gán giá trị cho một biến chỉ đọc, xảy ra lỗi và lệnh thoát với trạng thái khác không. "
Dennis Williamson

1

Nếu bạn đang làm foo=barecho $foo trên một dòng, nó sẽ không hoạt động. Bạn sẽ phải làm một trong ba điều.

  1. Chạy chúng như các lệnh riêng biệt. I E: foo=bar Đi vào echo $foo

  2. Chạy chúng trên một dòng, nhưng với một dấu chấm phẩy giữa hai. I E: foo=bar; echo $foo

  3. Tương tự như số 2, nhưng với ký hiệu kép. I E: foo=bar && echo $foo

Sự khác biệt giữa 2 và 3 là 3 sẽ chỉ thực thi echo $foo nếu foo=bar đã thành công.


Cảm ơn, nhưng tôi biết làm thế nào để giải quyết vấn đề. Tôi chỉ quan tâm đến ví dụ tôi cung cấp.
cYrus

+1: Mặc dù vậy, bộ thay thế đẹp. Điều này có thể có ích cho một ai đó.
cYrus


0

Một cách thích hợp để làm điều đó sẽ là:

foo=bar sh -c 'echo $foo'
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.