Mengapa saya tidak bisa menggunakan variabel sebagai awalan pada perintah untuk mengatur variabel lingkungan?

11

Biasanya, dimungkinkan untuk mengatur variabel lingkungan untuk suatu perintah dengan mengawalinya seperti ini:

hello=hi bash -c 'echo $hello'

Saya juga tahu bahwa kita bisa menggunakan variabel untuk mengganti setiap bagian dari permintaan perintah seperti berikut:

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

Saya sangat terkejut mengetahui bahwa Anda tidak dapat menggunakan variabel untuk mengawali perintah untuk mengatur variabel lingkungan. Kasus cobaan:

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

Mengapa saya tidak bisa mengatur variabel lingkungan menggunakan variabel? Apakah awalan merupakan bagian khusus? Saya bisa membuatnya bekerja dengan menggunakan eval di depan, tetapi saya masih tidak mengerti mengapa. Saya menggunakan bash 4.4.

wbkang
sumber
1
Anda bisa menggunakan, envbukan eval, IIRC mana yang lebih aman, tetapi lebih lambat.
wjandrea

Jawaban:

14

Saya menduga ini adalah bagian dari urutan yang menangkap Anda:

Kata-kata yang bukan penugasan atau pengarahan variabel diperluas (lihat Ekspansi Shell). Jika ada kata yang tersisa setelah ekspansi, kata pertama diambil sebagai nama perintah dan kata-kata yang tersisa adalah argumen

Itu dari manual referensi Bash di bagian Ekspansi Perintah Sederhana.

Dalam cmd=bashcontoh tersebut, tidak ada variabel lingkungan yang ditetapkan, dan bash memproses baris perintah melalui ekspansi parameter, meninggalkan bash -c "echo hi".

Dalam prefix=hello=hicontoh ini, tidak ada lagi penugasan variabel dalam pass pertama, jadi pemrosesan berlanjut ke ekspansi parameter, menghasilkan kata pertama hello=hi.

Setelah tugas variabel telah diproses, mereka tidak diproses ulang selama eksekusi perintah.

Lihat pemrosesan dan hasilnya di bawah set -x:

$ 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

Untuk variasi yang lebih aman dari "ekspansi variabel" -as- "variabel lingkungan" daripada eval, pertimbangkan saran wjandrea tentangenv :

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

Ini bukan semata-mata penugasan variabel baris perintah, karena kita menggunakan envfungsi utama utilitas untuk menugaskan variabel lingkungan ke suatu perintah, tetapi itu mencapai tujuan yang sama. The $prefixvariabel diperluas selama pengolahan baris perintah, memberikan nama = nilai env, yang dibagikan bersama untuk bash.

Jeff Schaller
sumber
3
Demikian pula, $foo=bar bash -c ...tidak akan berfungsi, karena $foo=barbukan penugasan variabel (apa pun nilainya $foo), karena $foo=bartidak cocok dengan name=valuepola penugasan variabel.
muru
3

Karena $prefixbukan tugas. @ Jeff memiliki penjelasan yang lebih panjang .

Anda bisa melakukan hal serupa dengan fungsi:

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

... dan Anda bahkan dapat menumpuknya, jika Anda suka:

$ foo() { foo=123 "$@"; }
$ bar() { bar=456 "$@"; }
$ foo bar bash -c 'echo "$bar $foo"'
456 123
ilkkachu
sumber