PowerShell: Đặt một biến môi trường chỉ cho một lệnh duy nhất


99

Trên Linux, tôi có thể làm:

$ FOO=BAR ./myscript

để gọi "myscript" với biến môi trường FOO đang được đặt.

Điều gì đó tương tự có thể xảy ra trong PowerShell, tức là không cần phải đặt biến trước, gọi lệnh, rồi hủy đặt biến lại?

Để rõ ràng hơn về trường hợp sử dụng của tôi - tôi không muốn sử dụng điều này như một phần của tập lệnh. Thay vào đó, tôi có một tập lệnh của bên thứ ba mà tôi có thể kiểm soát hành vi bằng cách sử dụng các biến môi trường, nhưng trong trường hợp này, không phải đối số dòng lệnh. Vì vậy, có thể luân phiên giữa việc nhập

$ OPTION=1 ./myscript

$ ./myscript

sẽ rất tiện dụng.


Tôi đoán câu hỏi của tôi sẽ là tại sao bạn cần phải làm điều này? Tôi nghĩ rằng có một giải pháp tốt hơn.
EBGreen 14/09/09

20
Đó thường không phải là một câu hỏi hữu ích, @EBGreen. Thực tế là khả năng có trong các shell UNIX cho thấy rằng có một công dụng cho nó. Ngoài ra trong đầu: kiểm soát tên người dùng và địa chỉ email mà git sử dụng cho các cam kết. Không có tùy chọn dòng lệnh cho những thứ đó - bạn phải đặt chúng trong ~ / .gitconfig, .git / config trong mỗi kho lưu trữ hoặc envars. Trong số các tùy chọn đó, các envars rõ ràng là dễ dàng hơn để thiết lập khi đang di chuyển (và ghi đè các giá trị trong tệp một cách thuận tiện). Vậy nếu tôi muốn thay đổi tên tác giả của mình cho một "git commit" trong powershell thì phải làm thế nào?
Mark Reed

2
Hoàn toàn đồng ý rằng việc hỏi tại sao điều này là cần thiết là vô nghĩa. Nó phổ biến như borscht khi thực thi tại dòng lệnh trên Linux và những người trong chúng ta giờ buộc phải đau khổ với powershell (một cơn ác mộng cú pháp nếu từng tồn tại) liên tục phải tìm kiếm câu trả lời cho các kỹ thuật hiển nhiên. Hầu hết thời gian, chúng thậm chí không tồn tại trong powershell trừ khi bạn tính việc viết các đoạn script dài để làm những việc tầm thường. Hãy đếm tôi vô cùng thất vọng với cái vỏ đó ...
Kim

2
Tính năng này đang được thảo luận cho PowerShell 6 .
Franklin Yu

1
Cảm ơn liên kết, @FranklinYu, nhưng tại thời điểm này, hy vọng sẽ có một phiên bản tương lai không xa sau v7.0 .
mklement0

Câu trả lời:


54

Nói chung, sẽ tốt hơn nếu chuyển thông tin đến tập lệnh thông qua một tham số hơn là một biến toàn cục (môi trường). Nhưng nếu đó là những gì bạn cần làm, bạn có thể làm theo cách này:

$env:FOO = 'BAR'; ./myscript

Biến môi trường $ env: FOO có thể bị xóa sau đó như sau:

Remove-Item Env:\FOO

2
Chỉ cần một suy nghĩ: Bạn có thể không tạo ra một quy trình PowerShell mới, đưa scriptblock vào đó thông qua tham số -Command? Bằng cách đó, bạn không phải dọn dẹp môi trường sau đó, vì điều đó sẽ được chứa trong quá trình con. Mặc dù tôi đang nói chuyện với PowerShell MVP nên điều này có thể không hoạt động :-)
Joey

2
Keith, chúng tôi có một push-environmentblock và pop-environmentblock trong Pscx cho chính xác kịch bản này ;-)
x0n

2
Johannes, điều đó cũng sẽ hiệu quả nhưng bằng cách nào đó có vẻ như gian lận. :-) PSCX Push / Pop-EnvironmentBlock (cái mà tôi đã thay đổi để hoạt động theo cách này) sẽ hoạt động nhưng nó không có hỗ trợ dọn dẹp tự động như scriptblock có.
Keith Hill

1
Bạn không cần phải đặt env:foolại về giá trị cũ của nó (có lẽ chưa được đặt) thay vì xóa nó?
chwarr

1
như @Joey đề cập, nếu bạn muốn làm env VAR sạch, bạn có thể: & {$pre = $env:foo; $env:foo = 'bar'; ./myscript; if ($pre) {$env:foo = $pre} else {Remove-Item env:\foo}... một số có thể nói trở nên cồng kềnh , nhưng sẽ tránh được các tác dụng phụ ...
Lucas

13

Tôi có đủ động lực về vấn đề này và tôi đã tiếp tục và viết một kịch bản cho nó: with-env.ps1

Sử dụng:

with-env.ps1 FOO=foo BAR=bar your command here

# Supports dot-env files as well
with-env.ps1 .\.env OTHER_ENV=env command here

Mặt khác, nếu bạn cài đặt Gow, bạn có thể sử dụng env.exenó có thể mạnh hơn một chút so với tập lệnh nhanh mà tôi đã viết ở trên.

Sử dụng:

env.exe FOO=foo BAR=bar your command here

# To use it with dot-env files
env.exe $(cat .env | grep.exe -v '^#') SOME_OTHER_ENV=val your command

4

Để thực hiện tương đương với cú pháp Unix, bạn không chỉ phải đặt biến môi trường mà còn phải đặt lại biến này về giá trị cũ sau khi thực hiện lệnh. Tôi đã hoàn thành điều này cho các lệnh phổ biến mà tôi sử dụng bằng cách thêm các chức năng tương tự như sau vào hồ sơ PowerShell của mình.

function cmd_special()
{
  $orig_master = $env:app_master
  $env:app_master = 'http://host.example.com'
  mycmd $args
  $env:app_master = $orig_master
}

Vì vậy, mycmdmột số tệp thực thi hoạt động khác nhau tùy thuộc vào giá trị của biến môi trường app_master. Bằng cách xác định cmd_special, bây giờ tôi có thể thực thi cmd_specialtừ dòng lệnh (bao gồm các tham số khác) với app_masterbiến môi trường được đặt ... và nó được đặt lại (hoặc thậm chí không được đặt) sau khi thực hiện lệnh.

Có lẽ, bạn cũng có thể làm điều này đặc biệt cho một lệnh gọi duy nhất.

& { $orig_master = $env:appmaster; $env:app_master = 'http://host.example.com'; mycmd $args; $env:app_master = $orig_master }

Nó thực sự sẽ dễ dàng hơn thế này, nhưng rõ ràng đây không phải là trường hợp sử dụng được PowerShell hỗ trợ sẵn. Có thể một phiên bản trong tương lai (hoặc chức năng của bên thứ ba) sẽ hỗ trợ trường hợp sử dụng này. Sẽ thật tuyệt nếu PowerShell có một lệnh ghép ngắn có thể thực hiện việc này, ví dụ:

with-env app_master='http://host.example.com' mycmd

Có lẽ một chuyên gia về PowerShell có thể gợi ý cách người ta có thể viết một lệnh ghép ngắn như vậy.


3

2 cách dễ dàng để làm điều đó trong một dòng:

$env:FOO='BAR'; .\myscript; $env:FOO=''
$env:FOO='BAR'; .\myscript; Remove-Item Env:\FOO

Chỉ là thông tin tóm tắt từ các câu trả lời khác (cảm ơn mọi người) không chứa một chữ lót thuần túy vì một số lý do.


0

Xét rằng CMD là CLI gốc trên nhân Windows (và vẫn là giao diện tự động hóa cho nhiều công cụ), bạn có thể đang thực thi tập lệnh PowerShell của mình powershell.exetừ dấu nhắc CMD hoặc giao diện chấp nhận các câu lệnh bảng điều khiển CMD.

Nếu bạn đang sử dụng -Filetham số để chuyển tập lệnh của mình powershell.exe, thì không thể sử dụng mã PowerShell nào khác để đặt biến môi trường cho tập lệnh truy cập, vì vậy thay vào đó bạn có thể đặt các biến môi trường của mình trong môi trường CMD trước khi gọi powershell.exe:

> set foo=bar && powershell.exe -File .\script.ps1

Một lệnh duy nhất &cũng sẽ hoạt động, nhưng sẽ cho phép lệnh tiếp tục nếu setkhông thành công vì lý do nào đó. (Điều này có khả thi không? Tôi không biết.)

Ngoài ra, có thể an toàn hơn khi đặt "foo=bar"trong dấu ngoặc kép để không có gì sau đó được chuyển đến setlàm nội dung biến.



-5

Bạn có thể xác định phạm vi các biến cho các hàm và tập lệnh.

$script:foo = "foo"
$foo
$function:functionVariable = "v"
$functionVariable

New-Variable cũng có tham số -scope nếu bạn muốn chính thức và khai báo biến của mình bằng cách sử dụng new-biến.


1
Hmmm ... Đừng nghĩ rằng câu trả lời này áp dụng ở đây. Biến PowerShell không phải là biến môi trường. Dựa trên câu hỏi, người hỏi không sử dụng các biến môi trường làm khoảng trống (giống như trong CMD [nếu đúng như vậy, câu trả lời này sẽ áp dụng]), nhưng cần phải thao tác với môi trường trước khi gọi lệnh bên ngoài và sau đó khôi phục môi trường sau đó (hoặc điều gì đó ảnh hưởng đến điều đó).
chwarr
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.