PowerShell: Menyetel variabel lingkungan untuk satu perintah saja

99

Di Linux, saya dapat melakukan:

$ FOO=BAR ./myscript

untuk memanggil "myscript" dengan variabel lingkungan FOO sedang disetel.

Apakah sesuatu yang serupa mungkin terjadi di PowerShell, yaitu tanpa harus mengatur variabel terlebih dahulu, memanggil perintah, dan kemudian menghapus variabel lagi?

Agar lebih jelas tentang kasus penggunaan saya - Saya tidak ingin menggunakan ini sebagai bagian dari skrip. Sebaliknya, saya memiliki skrip pihak ketiga yang perilakunya dapat saya kendalikan menggunakan variabel lingkungan, tetapi, dalam kasus ini, bukan argumen baris perintah. Jadi bisa bergantian antar mengetik

$ OPTION=1 ./myscript

dan

$ ./myscript

akan sangat berguna.

miracle2k
sumber
Saya kira pertanyaan saya adalah mengapa Anda perlu melakukan ini? Saya akan berpikir bahwa ada solusi yang lebih baik.
EBGreen
20
Itu biasanya bukan pertanyaan yang membantu, @EBGreen. Fakta bahwa kapabilitas yang ada di shell UNIX menunjukkan bahwa ada kegunaannya. Di luar kepala saya: mengontrol nama pengguna dan alamat email yang digunakan git untuk melakukan. Tidak ada opsi baris perintah untuk itu - Anda harus mengaturnya di ~ / .gitconfig, .git / config di setiap repositori, atau envars. Dari opsi tersebut, envars jelas lebih mudah untuk disetel saat itu juga (dan dengan mudah menimpa nilai dalam file). Jadi jika saya ingin mengubah nama pengarang saya untuk satu "git commit" di PowerShell, bagaimana cara melakukannya?
Mark Reed
2
Sepenuhnya setuju bahwa menanyakan mengapa hal ini diperlukan tidak ada gunanya. Hal ini sama lazimnya dengan borscht ketika mengeksekusi pada baris perintah di Linux dan kita yang dipaksa sekarang menderita dengan PowerShell (mimpi buruk sintaksis jika pernah ada) terus-menerus harus mencari jawaban untuk teknik yang jelas. Sebagian besar waktu, mereka bahkan tidak ada di PowerShell kecuali Anda menghitung menulis skrip panjang untuk melakukan hal-hal sepele. Hitung aku sangat frustrasi dengan cangkang itu ...
Kim
2
Fitur ini sedang dibahas untuk PowerShell 6 .
Franklin Yu
1
Terima kasih untuk tautannya, @FranklinYu, tetapi pada titik ini semoga akan menjadi versi masa depan yang tidak terlalu jauh setelah v7.0 .
mklement0

Jawaban:

55

Secara umum, akan lebih baik untuk meneruskan info ke skrip melalui parameter daripada variabel global (lingkungan). Tetapi jika itu yang perlu Anda lakukan, Anda dapat melakukannya dengan cara ini:

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

Variabel lingkungan $ env: FOO dapat dihapus nanti seperti:

Remove-Item Env:\FOO
Keith Hill
sumber
2
Hanya pemikiran: Tidak bisakah Anda menelurkan proses PowerShell baru, menyerahkan scriptblock ke dalamnya melalui parameter -Command? Dengan begitu Anda tidak perlu membersihkan lingkungan setelahnya, karena itu akan terkandung dalam proses anak. Meskipun saya sedang berbicara dengan PowerShell MVP jadi ini mungkin tidak berhasil :-)
Joey
2
Keith, kami memiliki push-environmentblock dan pop-environmentblock di Pscx untuk skenario ini ;-)
x0n
2
Johannes, itu akan berhasil juga tapi sepertinya curang. :-) PSCX Push / Pop-EnvironmentBlock (yang saya ubah agar berfungsi dengan cara ini) akan bekerja tetapi tidak memiliki dukungan pembersihan otomatis yang dimiliki scriptblock.
Keith Hill
1
Tidakkah Anda perlu menyetel env:fookembali ke nilai lamanya (mungkin tidak disetel) daripada menghapusnya?
chwarr
1
seperti yang disebutkan @Joey, jika Anda ingin melakukan env vars dengan bersih, Anda dapat: & {$pre = $env:foo; $env:foo = 'bar'; ./myscript; if ($pre) {$env:foo = $pre} else {Remove-Item env:\foo}... beberapa mungkin mengatakan berat , tetapi akan menghindari efek samping ...
Lucas
13

Saya cukup termotivasi tentang masalah ini sehingga saya melanjutkan dan menulis skrip untuk itu: with-env.ps1

Pemakaian:

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

Di sisi lain, jika Anda menginstal Gow, Anda dapat menggunakan env.exeyang mungkin sedikit lebih kuat daripada skrip cepat yang saya tulis di atas.

Pemakaian:

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
kizzx2
sumber
5

2 cara mudah melakukannya dalam satu baris:

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

Baru saja meringkas informasi dari jawaban lain (terima kasih teman-teman) yang tidak mengandung satu kalimat murni untuk beberapa alasan.

Alexander Fadeev
sumber
4

Untuk mencapai padanan sintaks Unix, Anda tidak hanya harus mengatur variabel lingkungan, tetapi Anda harus mengatur ulang ke nilai semula setelah menjalankan perintah. Saya telah menyelesaikan ini untuk perintah umum yang saya gunakan dengan menambahkan fungsi yang mirip dengan berikut ini ke profil PowerShell saya.

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

Begitu mycmdjuga beberapa executable yang beroperasi secara berbeda tergantung pada nilai variabel lingkungan app_master. Dengan mendefinisikan cmd_special, saya sekarang dapat mengeksekusi cmd_specialdari baris perintah (termasuk parameter lain) dengan app_mastervariabel lingkungan set ... dan itu akan direset (atau bahkan tidak disetel) setelah eksekusi perintah.

Agaknya, Anda juga bisa melakukan ad-hoc ini untuk satu doa.

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

Seharusnya lebih mudah dari ini, tetapi tampaknya ini bukan kasus penggunaan yang sudah didukung oleh PowerShell. Mungkin versi yang akan datang (atau fungsi pihak ketiga) akan memfasilitasi kasus penggunaan ini. Alangkah baiknya jika PowerShell memiliki cmdlet yang akan melakukan ini, misalnya:

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

Mungkin seorang guru PowerShell dapat menyarankan bagaimana seseorang dapat menulis cmdlet semacam itu.

Jason R. Coombs
sumber
0

Mengingat CMD adalah CLI asli pada kernel Windows (dan masih merupakan antarmuka otomatisasi untuk banyak alat), Anda dapat menjalankan skrip PowerShell Anda dengan powershell.exe dari prompt CMD atau antarmuka yang menerima pernyataan konsol CMD.

Jika Anda menggunakan -Fileparameter untuk meneruskan skrip Anda powershell.exe, tidak ada kode PowerShell lain yang dapat digunakan untuk menyetel variabel lingkungan untuk diakses skrip, jadi Anda dapat menyetel variabel lingkungan Anda di lingkungan CMD sebelum memanggil powershell.exe:

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

Satu &juga akan berfungsi, tetapi akan memungkinkan perintah untuk melanjutkan jika setgagal karena beberapa alasan. (Apakah ini mungkin? Saya tidak tahu.)

Selain itu, mungkin lebih aman untuk memasukkan "foo=bar"tanda kutip sehingga tidak ada yang mengikuti yang diteruskan setsebagai konten variabel.

NReilingh
sumber
-5

Anda dapat mengatur variabel ke fungsi dan skrip.

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

New-Variable juga memiliki parameter -scope jika Anda ingin formal dan mendeklarasikan variabel Anda menggunakan variabel-baru.

Andy Schneider
sumber
1
Hmmm ... Jangan kira jawaban ini berlaku di sini. Variabel PowerShell bukanlah variabel lingkungan. Berdasarkan pertanyaan tersebut, penanya tidak menggunakan variabel lingkungan sebagai ruang awal (seperti yang akan dilakukan di CMD [jika itu masalahnya, jawaban ini akan berlaku]), tetapi perlu memanipulasi lingkungan sebelum menjalankan perintah eksternal dan kemudian memulihkan lingkungan sesudahnya (atau sesuatu seperti itu).
chwarr