Pertimbangkan cuplikan ini:
$ SOMEVAR=AAA
$ echo zzz $SOMEVAR zzz
zzz AAA zzz
Di sini saya telah mengatur $SOMEVAR
ke AAA
baris pertama - dan ketika saya menggemakannya di baris kedua, saya mendapatkan AAA
isinya seperti yang diharapkan.
Tetapi kemudian, jika saya mencoba menentukan variabel pada baris perintah yang sama dengan echo
:
$ SOMEVAR=BBB echo zzz $SOMEVAR zzz
zzz AAA zzz
... Saya tidak mendapatkan BBB
seperti yang saya harapkan - saya mendapatkan nilai lama ( AAA
).
Apakah seharusnya seperti ini? Jika demikian, mengapa Anda dapat menentukan variabel like LD_PRELOAD=/... program args ...
dan membuatnya berfungsi? Apa yang saya lewatkan?
bash
environment-variables
echo
sdaau
sumber
sumber
LD_PRELOAD
karya adalah bahwa variabel diatur dalam program lingkungan - tidak dalam baris perintah.Jawaban:
Apa yang Anda lihat adalah perilaku yang diharapkan. Masalahnya adalah bahwa shell induk mengevaluasi
$SOMEVAR
pada baris perintah sebelum memanggil perintah dengan lingkungan yang dimodifikasi. Anda perlu mendapatkan evaluasi$SOMEVAR
ditangguhkan sampai lingkungan ditetapkan.Pilihan langsung Anda meliputi:
SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz
.SOMEVAR=BBB sh -c 'echo zzz $SOMEVAR zzz'
.Keduanya menggunakan tanda kutip tunggal untuk mencegah shell induk mengevaluasi
$SOMEVAR
; itu hanya dievaluasi setelah disetel di lingkungan (sementara, selama durasi perintah tunggal).Pilihan lain adalah dengan menggunakan notasi sub-shell (seperti yang juga disarankan oleh Marcus Kuhn dalam jawabannya ):
(SOMEVAR=BBB; echo zzz $SOMEVAR zzz)
Variabel diatur hanya di sub-shell
sumber
Masalahnya, Ditinjau Kembali
Sejujurnya, manual ini membingungkan dalam hal ini. The pengguna GNU Bash mengatakan:
Jika Anda benar-benar mengurai kalimat tersebut, maksudnya adalah lingkungan untuk perintah / fungsi diubah, tetapi bukan lingkungan untuk proses induk. Jadi, ini akan berhasil:
karena lingkungan untuk perintah env telah dimodifikasi sebelum dijalankan. Namun, ini tidak akan berhasil:
$ set -x; TESTVAR=bbb echo aaa $TESTVAR ccc + TESTVAR=bbb + echo aaa ccc aaa ccc
karena ketika ekspansi parameter dilakukan oleh shell.
Langkah Penerjemah
Bagian lain dari masalah ini adalah Bash menentukan langkah-langkah berikut untuk penerjemahnya:
Apa yang terjadi di sini adalah bahwa bawaan tidak mendapatkan lingkungan eksekusinya sendiri, jadi mereka tidak pernah melihat lingkungan yang dimodifikasi. Selain itu, perintah-perintah sederhana (misalnya / bin / echo) yang mendapatkan ennvironment dimodifikasi (yang mengapa contoh env bekerja) tetapi ekspansi shell berlangsung di saat lingkungan pada langkah # 4.
Dengan kata lain, Anda tidak mengirimkan 'aaa $ TESTVAR ccc' ke / bin / echo; Anda meneruskan string yang diinterpolasi (seperti yang diperluas di lingkungan saat ini) ke / bin / echo. Dalam kasus ini, karena lingkungan saat ini tidak memiliki TESTVAR , Anda cukup meneruskan 'aaa ccc' ke perintah.
Ringkasan
Dokumentasinya bisa jauh lebih jelas. Untung ada Stack Overflow!
Lihat juga
http://www.gnu.org/software/bash/manual/bashref.html#Command-Execution-Environment
sumber
FOO=foo eval 'echo $FOO'
mencetakfoo
seperti yang diharapkan. Artinya, Anda dapat melakukan hal-hal sepertiIFS="..." read ...
.Untuk mencapai apa yang Anda inginkan, gunakan
( SOMEVAR=BBB; echo zzz $SOMEVAR zzz )
Alasan:
Anda harus memisahkan penetapan dengan titik koma atau baris baru dari perintah berikutnya, jika tidak maka tidak akan dijalankan sebelum perluasan parameter terjadi untuk perintah berikutnya (gema).
Anda perlu membuat tugas di dalam lingkungan subkulit , untuk memastikannya tidak bertahan di luar baris saat ini.
Solusi ini lebih pendek, lebih rapi dan lebih efisien daripada beberapa solusi lain yang disarankan, khususnya ini tidak menciptakan proses baru.
sumber
(export SOMEVAR=BBB; python -c "from os import getenv; print getenv('SOMEVAR')")
SOMEVAR=BBB python -c "from os import getenv; print getenv('SOMEVAR')"
Alasannya adalah ini menetapkan variabel lingkungan untuk satu baris. Tapi,
echo
jangan lakukan ekspansi,bash
ya. Oleh karena itu, variabel Anda sebenarnya diperluas sebelum perintah dijalankan, meskipunSOME_VAR
adalahBBB
dalam konteks perintah echo.Untuk melihat efeknya, Anda dapat melakukan sesuatu seperti:
$ SOME_VAR=BBB bash -c 'echo $SOME_VAR' BBB
Di sini variabel tidak diperluas sampai proses anak dijalankan, sehingga Anda melihat nilai yang diperbarui. jika Anda memeriksa
SOME_VARIABLE
lagi di shell induk, itu masihAAA
seperti yang diharapkan.sumber
SOMEVAR=BBB; echo zzz $SOMEVAR zzz
Gunakan ; untuk memisahkan pernyataan yang ada di baris yang sama.
sumber
LD_PRELOAD
dan seperti itu dapat bekerja di depan eksekusi tanpa titik koma, meskipun ... Banyak terima kasih lagi - tepuk tangan!Berikut salah satu alternatifnya:
SOMEVAR=BBB && echo zzz $SOMEVAR zzz
sumber
&&
atau;
untuk memisahkan perintah, tugas tetap ada, yang bukan merupakan perilaku OP yang diinginkan. Markus Kuhn memiliki versi yang benar dari jawaban ini.