Bagaimana cara menyimpan output dari perintah yang mengubah lingkungan menjadi variabel?
Saya menggunakan bash shell.
Anggap saya punya:
function f () { a=3; b=4 ; echo "`date`: $a $b"; }
Dan sekarang, saya bisa menggunakan perintah untuk menjalankan f
:
$ a=0; b=0; f; echo $a; echo $b; echo $c
Sat Jun 28 21:27:08 CEST 2014: 3 4
3
4
tapi saya ingin menyimpan output f
ke variabel c
, jadi saya mencoba:
a=0; b=0; c=""; c=$(f); echo $a; echo $b; echo $c
tapi sayangnya, saya punya:
0
0
Sat Jun 28 21:28:03 CEST 2014: 3 4
jadi saya tidak punya perubahan lingkungan di sini.
Bagaimana cara menyimpan output dari perintah (tidak hanya berfungsi) ke variabel dan menyimpan perubahan lingkungan?
Saya tahu itu $(...)
membuka subkulit baru dan itulah masalahnya, tetapi apakah mungkin untuk melakukan beberapa solusi?
bash
environment-variables
output
faramir
sumber
sumber
$a
dan$b
merupakan variabel lokal dif
fungsi Anda . Anda bisaexport
melakukannya, tetapi itu tampak samar.…; f; echo $a; …
hasilnya3
digaungkan, begituf
juga memodifikasi variabel shell (dan bukan hanya variabel lokalnya sendiri).Jawaban:
Jika Anda menggunakan Bash 4 atau lambat, Anda dapat menggunakan coprocesses :
akan menampilkan
coproc
membuat proses baru menjalankan perintah yang diberikan (di sini,cat
). Ini menyimpan PID ke dalamCOPROC_PID
dan deskriptor file output / input standar ke dalam arrayCOPROC
(sepertipipe(2)
, atau lihat di sini atau di sini ).Di sini kita menjalankan fungsinya dengan output standar yang menunjuk pada coprocess kita yang berjalan
cat
, dan kemudianread
darinya. Karenacat
hanya meludahkan inputnya kembali, kita mendapatkan output fungsi ke dalam variabel kita.exec {COPROC[1]}>&-
tutup saja deskriptor file agarcat
tidak terus menunggu selamanya.Perhatikan bahwa
read
hanya perlu satu baris setiap kali. Anda dapat menggunakanmapfile
untuk mendapatkan array baris, atau cukup gunakan deskriptor file namun Anda ingin menggunakannya dengan cara yang berbeda.exec {COPROC[1]}>&-
karya dalam versi saat ini dari Bash, namun versi sebelumnya 4-series mengharuskan Anda untuk menyimpan file descriptor ke dalam variabel sederhana pertama:fd=${COPROC[1]}; exec {fd}>&-
. Jika variabel Anda tidak disetel, itu akan menutup output standar.Jika Anda menggunakan Bash versi 3-seri, Anda bisa mendapatkan efek yang sama
mkfifo
, tetapi itu tidak jauh lebih baik daripada menggunakan file aktual pada saat itu.sumber
exec {COPROC[1]}>&-
perintah (setidaknya kadang-kadang) segera menghentikan proses , sehingga hasilnya tidak lagi tersedia untuk dibaca.coproc { cat; sleep 1; }
tampaknya bekerja lebih baik. (Anda mungkin perlu menambah1
jika Anda membaca lebih dari satu baris.)Jika Anda sudah mengandalkan tubuh
f
mengeksekusi di shell yang sama dengan pemanggil, dan dengan demikian dapat memodifikasi variabel sepertia
danb
, mengapa tidak membuat fungsi hanya diaturc
juga? Dengan kata lain:Salah satu alasan yang mungkin adalah bahwa variabel output perlu memiliki nama yang berbeda (c1, c2, dll) ketika dipanggil di tempat yang berbeda, tetapi Anda bisa mengatasinya dengan mengatur fungsi c_TEMP dan meminta penelepon melakukannya
c1=$c_TEMP
dll.sumber
Ini kluge, tapi cobalah
(dan, secara opsional,
rm c.file
).sumber
mktemp
, tetapi saya ingin tidak membuat file tambahan.Cukup tetapkan semua variabel dan tulis output pada saat yang sama.
Sekarang jika Anda melakukannya:
Output Anda adalah:
Perhatikan bahwa ini sepenuhnya kode portabel POSIX. Saya awalnya ditetapkan
c=
ke''
string nol karena ekspansi parameter membatasi penugasan variabel bersamaan + evaluasi untuk hanya numerik (seperti$((var=num))
) atau dari nilai nol atau tidak ada - atau, dengan kata lain, Anda tidak dapat secara bersamaan mengatur dan mengevaluasi variabel ke string yang arbitrer jika variabel itu sudah diberi nilai. Jadi saya hanya memastikan bahwa itu kosong sebelum mencoba. Jika saya tidak mengosongkanc
sebelum mencoba untuk menetapkan ekspansi itu hanya akan mengembalikan nilai lama.Hanya untuk menunjukkan:
newval
adalah tidak ditugaskan untuk$c
inline karenaoldval
diperluas ke${word}
, sedangkan inline$((
aritmatika=
tugas))
selalu terjadi. Tetapi jika$c
tidak adaoldval
dan kosong atau tidak disetel ...... kemudian
newval
ditugaskan dan diperluas ke$c
.Semua cara lain untuk melakukan ini melibatkan beberapa bentuk evaluasi sekunder. Sebagai contoh, katakanlah saya ingin menetapkan output
f()
ke variabel bernamaname
pada satu titik danvar
di titik lain. Seperti yang ditulis saat ini, ini tidak akan berfungsi tanpa mengatur var dalam ruang lingkup penelepon. Namun, cara yang berbeda dapat terlihat seperti ini:Saya telah memberikan contoh yang diformat lebih baik di bawah ini, tetapi, disebut seperti di atas, keluarannya adalah:
Atau dengan
$ENV
argumen atau perbedaan :Mungkin hal paling sulit untuk dilakukan dengan benar ketika mengevaluasi dua kali adalah memastikan bahwa variabel tidak memecah tanda kutip dan mengeksekusi kode acak. Semakin banyak variabel dievaluasi semakin sulit. Ekspansi parameter sangat membantu di sini, dan menggunakan
export
sebagai lawaneval
jauh lebih aman.Dalam contoh di atas
f()
pertama memberikan$fout
yang''
nol tali dan kemudian menetapkan params posisi ke tes untuk nama variabel yang valid. Jika kedua pengujian tidak lulus pesan dipancarkan kestderr
dan nilai defaultfout
ditugaskan untuk$fout_name
. Terlepas dari tes, bagaimanapun,$fout_name
selalu ditugaskan untuk salah satufout
atau nama yang Anda tentukan$fout
dan, dan opsional, nama yang Anda tentukan selalu diberi nilai output dari fungsi. Untuk menunjukkan ini, saya menulisfor
lingkaran kecil ini :Memainkan beberapa dengan nama variabel dan ekspansi parameter. Jika Anda memiliki pertanyaan, tanyakan saja. Itu hanya menjalankan beberapa baris yang sama dalam fungsi yang sudah diwakili di sini. Perlu disebutkan setidaknya bahwa variabel
$a
dan$b
berperilaku berbeda tergantung pada apakah mereka didefinisikan pada doa, atau sudah ditetapkan. Namun,for
hampir tidak melakukan apa-apa selain memformat kumpulan data dan disediakan olehf()
. Lihat:sumber