Tại sao tôi không thể sử dụng biến làm tiền tố cho lệnh để đặt biến môi trường?


11

Thông thường, có thể đặt biến môi trường cho lệnh bằng cách thêm tiền tố vào như sau:

hello=hi bash -c 'echo $hello'

Tôi cũng biết rằng chúng ta có thể sử dụng một biến để thay thế bất kỳ phần nào của lệnh gọi như sau:

$ cmd=bash
$ $cmd -c "echo hi" # equivalent to bash -c "echo hi"

Tôi đã rất ngạc nhiên khi phát hiện ra rằng bạn không thể sử dụng một biến để tiền tố một lệnh để đặt một biến môi trường. Trường hợp thử nghiệm:

$ prefix=hello=hi
$ echo $prefix # prints hello=hi
$ $prefix bash -c 'echo $hello'
hello=hi: command not found

Tại sao tôi không thể đặt biến môi trường bằng biến? Là phần tiền tố là một phần đặc biệt? Tôi đã có thể làm cho nó hoạt động bằng cách sử dụng eval ở phía trước, nhưng tôi vẫn không hiểu tại sao. Tôi đang sử dụng bash 4.4.


1
Bạn có thể sử dụng envthay vì eval, IIRC nào an toàn hơn, nhưng chậm hơn.
wjandrea

Câu trả lời:


14

Tôi nghi ngờ đây là một phần của chuỗi bắt bạn:

Các từ không phải là bài tập biến đổi hoặc chuyển hướng được mở rộng (xem phần Mở rộng Shell). Nếu bất kỳ từ nào còn lại sau khi mở rộng, từ đầu tiên được coi là tên của lệnh và các từ còn lại là các đối số

Đó là từ tài liệu tham khảo Bash trong phần Mở rộng lệnh đơn giản.

Trong cmd=bashví dụ này, không có biến môi trường nào được đặt và bash xử lý dòng lệnh thông qua việc mở rộng tham số, để lại bash -c "echo hi".

Trong prefix=hello=hiví dụ, một lần nữa không có phép gán biến trong lần đầu tiên, vì vậy việc xử lý tiếp tục mở rộng tham số, dẫn đến một từ đầu tiên hello=hi.

Khi các phép gán biến đã được xử lý, chúng không được xử lý lại trong quá trình thực thi lệnh.

Xem xử lý và kết quả của nó dưới set -xđây:

$ prefix=hello=hi
+ prefix=hello=hi
$ $prefix bash -c 'echo $hello'
+ hello=hi bash -c 'echo $hello'
-bash: hello=hi: command not found
$ hello=42 bash -c 'echo $hello'
+ hello=42
+ bash -c 'echo $hello'
42

Đối với một biến thể an toàn hơn của "mở rộng biến" -as- "biến môi trường" hơn eval, hãy xem xét đề xuất của wjandrea vềenv :

prefix=hello=hi
env "$prefix" bash -c 'echo "$hello"'
hi

Đây không hoàn toàn là một phép gán biến dòng lệnh, vì chúng ta đang sử dụng envchức năng chính của tiện ích là gán các biến môi trường cho một lệnh, nhưng nó hoàn thành cùng một mục tiêu. Các $prefixbiến được mở rộng trong việc xử lý các dòng lệnh, cung cấp tên = giá trị env, ai đi qua nó cùng đến bash.


3
Tương tự, $foo=bar bash -c ...sẽ không hoạt động, bởi vì $foo=barkhông phải là một phép gán biến (dù là giá trị của $foo), bởi vì $foo=barkhông phù hợp với name=valuemẫu cho phép gán biến.
muru

3

Bởi vì $prefixkhông phải là một nhiệm vụ. @Jeff có lời giải thích dài hơn .

Bạn có thể làm một điều tương tự với một chức năng thay thế:

$ prefix() { hello=hi "$@"; }
$ prefix bash -c 'echo "$hello"'
hi

... và bạn thậm chí có thể xếp chúng, nếu bạn thích:

$ foo() { foo=123 "$@"; }
$ bar() { bar=456 "$@"; }
$ foo bar bash -c 'echo "$bar $foo"'
456 123
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.