Saya ingin skrip saya membaca file yang berisi pasangan kunci / nilai variabel lingkungan untuk diatur, lalu mengaturnya.
Sejauh ini, saya punya ini:
#!/bin/bash
cat $1 | while read kv
do
key=${kv%=*}
val=`echo ${kv#*=} | sed 's/^"\|"$//g'`
export $key="$val"
done
Dan saya ingin membaca file seperti ini:
XAUTHLOCALHOSTNAME="localhost"
DISPLAY=":0"
XAUTHORITY="/tmp/some-XAuthority"
Saya hanya perlu variabel ini dalam cakupan selama durasi skrip, jadi saya tidak perlu menyelesaikan masalah pengaturan variabel dalam skrip untuk cakupan induk .
Dari pengujian saya, saya pikir masalahnya terletak pada export $key="$val"
, jadi saya pikir saya hanya perlu pengganti untuk jalur itu.
bash
shell-script
environment-variables
palswim
sumber
sumber
key=${kv%%=*}
lebih baik daripadakey=${kv%=*}
karena %% dan ## berbeda dari% dan # untuk apakah bagian yang dihapus adalah bagian yang dapat dilepas terpendek atau terpanjangJawaban:
export $key=$val
harus bekerja dengan baikbash
. Saya menduga masalah Anda adalah pipanya (|
). Semua perintah dalam pipa dieksekusi dalam subkulit. Dalam contoh Anda, contohbash
yang menjalankan skrip Anda akan memotong 2 subkulit: satu untukcat $1
dan lain untukwhile read ...
. Variabel ditugaskan dan diekspor dalam subkulit yang menjalankan loop sementara, dan kemudian semuanya segera dibuang ketika subkulit keluar. Salah satu cara untuk memperbaikinya adalah dengan tidak menelurkan subkulit sama sekali. Alih-alih menggunakan kucing yang tidak berguna , coba pengalihan saja:BashFAQ 24 menjelaskan ini dengan lebih rinci.
Pendekatan alternatif adalah hanya sumber file, dengan ekspor dilemparkan ke:
The
<( )
adalah proses substitusi.Sebagai catatan peringatan, karena Anda membaca variabel lingkungan dari argumen, Anda harus memastikan bahwa file argumen
$1
adalah sumber tepercaya sehingga tidak dapat melakukan hal-hal buruk pada skrip Anda.sumber
cat
. Tapi, skrip dengan pengalihan berfungsi sekarang, terima kasih!( jw013 telah memberikan jawaban yang benar , tetapi saya ingin menunjukkan beberapa masalah lagi.)
Sisi kanan pipa berjalan di subkulitnya sendiri di bash (dan juga sebagian besar shell lainnya, pengecualiannya adalah ATT ksh dan zsh). Jadi Anda mengatur variabel lingkungan di subkulit yang mengeksekusi loop, tetapi tidak dalam proses shell utama.
Di sini ada perbaikan yang mudah yaitu mengganti penggunaan yang tidak berguna
cat
dengan pengalihan:Secara umum, jika Anda perlu memproses input, letakkan loop dan sisa skrip (setidaknya bagian yang membutuhkan variabel yang diubah) di dalam blok.
Perhatikan bahwa secara umum,
while read line; do …
tidak cukup iterate pada jalur input. Lihat Mengapawhile IFS= read
sering digunakan, bukanIFS=; while read..
? untuk penjelasan. Ungkapan yang benar untuk beralih pada jalur input adalahDi sini, penghapusan spasi putih depan dan akhir tidak menjadi masalah karena seharusnya tidak ada input sampel yang diberikan, tetapi Anda mungkin perlu
-r
menghindari ekspansi backslash. Mungkin sajawhile read line
sebenarnya cara yang benar untuk membaca input Anda (tapi saya curiga hanya jika nilai variabel tidak mengandung baris baru). Mungkin juga format input Anda ambigu atau lebih rumit untuk diuraikan. Periksa apa yang terjadi jika salah satu nilai variabel berisi karakter baris baru, kutipan ganda atau garis miring terbalik.Satu titik di mana Anda benar-benar mengacaukan input adalah ketika Anda mengekstrak nilainya:
Pertama, Anda perlu menggunakan tanda kutip ganda sekitar substitusi variabel:
echo "${kv#*=}"
; jika tidak, shell melakukan pemisahan kata dan nama file generasi (yaitu globbing) di atasnya. Kedua,echo
bukan cara yang dapat diandalkan untuk mencetak string, karena beberapa string yang dimulai dengan a-
diperlakukan sebagai opsi, dan beberapa shell melakukan ekspansi backslash pada argumen. Cara yang andal dan portabel untuk mencetak string adalahprintf %s "${kv#*=}"
. Juga, jika nilainya mencakup beberapa baris, program sed akan bertindak pada masing-masing secara terpisah, yang mana salah. Ini diperbaiki, tapi ada metode yang lebih mudah, yaitu dengan menggunakan fasilitas manipulasi string shell:val=${kv#*=}; val=${val#\"}; val=${val%\"}
.Dengan asumsi bahwa input Anda diurai dengan benar dengan sebuah dataran
read
, berikut ini adalah cara yang lebih sederhana untuk menguraikannya, mengambil keuntungan dariIFS
pengaturan untuk membagi setiap baris:sumber
Pilihan lain yang bagus adalah dengan meletakkannya
export
di file dan sumbernya:lalu:
sumber
/ env
naskah
sumber