Bỏ đặt một biến môi trường cho một lệnh


24

Tôi có thể chạy ENV_VAR=value commandđể chạy commandvới một giá trị cụ thể cho ENV_VAR. Là những gì tương đương với bỏ đặt ENV_VARcho command?


7
Ngoài ra: commandlà một sự lựa chọn đáng tiếc của các trình giữ chỗ, vì thực sự một lệnh tích hợp theo tên đó. mycommandhoặc somecommandnhư vậy có thể là một thói quen tốt hơn để tham gia.
Charles Duffy

@CharlesDuffy, tôi thường sử dụng cmdcho điều đó.
Stéphane Chazelas

Câu trả lời:


35

Khác với -itùy chọn xóa sạch toàn bộ môi trường, POSIX envkhông cung cấp bất kỳ cách nào để bỏ đặt một biến.

Tuy nhiên, với một vài envtriển khai (bao gồm busyboxít nhất là GNU, 'và FreeBSD), bạn có thể thực hiện:

env -u ENV_VAR command

Cái nào sẽ hoạt động trong việc loại bỏ mọi trường hợp của một ENV_VARbiến khỏi môi trường (lưu ý rằng nó không hoạt động với biến môi trường với một tên trống ( env -u ''có thể gây ra lỗi hoặc không hiệu quả tùy thuộc vào việc triển khai mặc dù tất cả đều chấp nhận env '=value', có thể là một hạn chế phát sinh bởi unsetenv()hàm C mà POSIX yêu cầu trả về lỗi cho chuỗi trống, trong khi không có giới hạn nào như vậy putenv())).

Có thể di chuyển (trong vỏ POSIX), bạn có thể làm:

(unset -v ENV_VAR; exec command)

(lưu ý rằng với một số shell, việc sử dụng execcó thể thay đổi commandđang chạy: chạy cái trong hệ thống tập tin thay vì chức năng hoặc ví dụ dựng sẵn (và sẽ bỏ qua aliasviệc mở rộng rõ ràng), như envtrên. Bạn muốn bỏ qua nó trong những trường hợp đó) .

Nhưng điều đó sẽ không hoạt động đối với các biến môi trường có tên không thể ánh xạ tới biến shell (lưu ý rằng một số shell như thế mkshsẽ loại bỏ các biến đó khỏi môi trường khi khởi động) hoặc các biến được đánh dấu chỉ đọc.

-vlà cho vỏ Bourne và bashunsetmà không -vthể bỏ đặt một ENV_VAR chức năng nếu không có biến bằng tên đó. Hầu hết các shell khác sẽ không hủy chức năng trừ khi bạn vượt qua -ftùy chọn. (không có khả năng tạo ra sự khác biệt trong thực tế).

(Cũng hãy cẩn thận với lỗi / lỗi sai của bash/ mksh/ yashngười unset, trong một số trường hợp có thể không bỏ đặt biến, nhưng tiết lộ biến trong phạm vi bên ngoài )

Nếu perlcó sẵn, bạn có thể làm:

perl -e 'delete $ENV{shift@ARGV}; exec @ARGV or die$!' ENV_VAR command

Mà sẽ làm việc ngay cả đối với biến môi trường với một tên trống.

Bây giờ tất cả những thứ đó sẽ không hoạt động nếu bạn muốn thay đổi biến môi trường cho hàm dựng sẵn hoặc hàm và không muốn chúng chạy trong một mạng con, như trong bash:

env -u LANG printf -v var %.3f 1.2 # would run /usr/bin/printf instead
(unset -v LANG; printf -v var %.3f 1.2) # changes to $var lost afterwards

(ở đây bỏ chọn LANG như một cách tiếp cận sai lầm trong việc đảm bảo .được sử dụng và được hiểu là dấu phân cách thập phân. Sẽ tốt hơn khi sử dụng LC_ALL=C printf...cho điều đó)

Với một số shell, thay vào đó, bạn có thể tạo một phạm vi cục bộ cho biến bằng cách sử dụng hàm:

without() {
  local "$1" # $1 variable declared as initially unset in bash¹
  shift
  "$@"
}
without LANG printf -v var %.3f 1.2

Với zsh, bạn cũng có thể sử dụng một chức năng ẩn danh:

(){local ENV_VAR; command}

Cách tiếp cận đó sẽ không hoạt động trong một số shell (như các shell dựa trên shell Almquist), người localkhông khai báo biến là không đặt ban đầu (nhưng kế thừa giá trị và thuộc tính). Trong những điều đó, bạn có thể làm local ENV_VAR; unset ENV_VAR, nhưng đừng làm điều đó trong mkshhoặc yash( typesetthay vì localcho điều đó) vì điều đó sẽ không hiệu quả, unsetsẽ chỉ hủy bỏ local.

Cũng lưu ý rằng trong bash, cục bộ ENV_VAR(ngay cả khi chưa đặt) sẽ giữ lại thuộc tính xuất . Vì vậy, nếu commandlà một hàm gán giá trị cho ENV_VAR, biến sẽ có sẵn trong môi trường của các lệnh được gọi sau đó. unset ENV_VARsẽ xóa thuộc tính đó. Hoặc bạn có thể sử dụng local +x ENV_VARnó cũng sẽ đảm bảo một bảng rõ ràng (trừ khi biến đó được khai báo chỉ đọc, nhưng sau đó bạn không thể làm gì về nó bash).


1
Đó là một câu hỏi riêng biệt, nhưng cái quái gì là một biến môi trường với một tên trống và bạn sẽ sử dụng nó như thế nào - ngay cả đối với một loại khai thác nào đó? Bạn sẽ không phải viết một chương trình đọc môi trường và đặc biệt tìm kiếm một cái gì đó như thế này chứ?
Joe

@Joe, thử ví dụ env '=foo' python -c 'import os; print os.environ[""]'. Tôi không mong đợi nhiều người muốn đặt một biến như thế.
Stéphane Chazelas

9

Không có tương đương trực tiếp như tôi biết; bạn có thể sử dụng một subshell:

(unset ENV_VAR; exec command)

(unset ENV_VAR; exec somecommand)nếu bạn muốn tương đương với bản gốc về hiệu quả (bằng cách tiêu thụ phần phụ). Như nó là, điều này thêm một ngã ba thêm.
Charles Duffy

1
@Charles thực sự, mặc dù một số shell thực hiện điều đó một cách tự động vì đây commandlà lệnh cuối cùng trong lệnh gọi subshell.
Stephen Kitt

+1 vì cách này đơn giản để nhập để sử dụng tương tác. Tôi sử dụng các lớp con cho các thay đổi một lần đối với môi trường vỏ cho lớp lót thay vì nhớ rằng đó là env -u.
Peter Cordes

0

Bạn có thể dùng ENV_VAR= command

Điều này không thực sự bỏ đặt biến, nhưng nó có thể hữu ích trong nhiều trường hợp (tập lệnh shell thường chỉ sử dụng test -nđể kiểm tra xem một biến có được đặt không):

$ export ENV_VAR=foo
$ mycommand
ENV_VAR: foo
$ ENV_VAR=bar mycommand
ENV_VAR: bar
$ ENV_VAR= mycommand
ENV_VAR: 
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.