Kemungkinan bug di Bash ?: foo () {echo “$ {var [0]}”; }; var = (bar baz) foo

22

OS : Ubuntu 16.04.3

Shell : Bash 4.3.48


Saya tahu itu mungkin untuk sementara mengubah konten variabel seperti var=value command, mungkin IFS= read -r varmerupakan kasus yang paling menonjol dari ini.

Dan, terima kasih kepada wiki Greg , saya juga mengerti:

# Why this
foo() { echo "$var"; }
var=value foo

# And this does work
var=value; echo "$var"

# But this doesn't
var=value echo "$var"

Apa yang luput dari pemahaman saya adalah ini:

$ foo() { echo "${var[0]}"; }
$ var=(bar baz) foo
(bar baz)

Sejauh yang saya tahu (dan mengikuti logika dari contoh sebelumnya), itu harus dicetak bar, bukan (bar baz).

Apakah ini hanya terjadi pada saya? Apakah ini perilaku yang dimaksudkan dan saya kehilangan sesuatu? Atau ini bug?

nxnev
sumber
3
Mungkin itu ada hubungannya dengan fakta bahwa bash tidak mendukung array sebagai variabel lingkungan?
Jesse_b
3
@Jesse_b Mungkin. Padahal ketika saya menjalankannya export var=(foo bar); echo "${var[0]}"mencetak foo, tidak (foo bar).
nxnev
1
Aneh, itu bekerja untuk saya juga. Dan menggunakannya exportmenunjukkan:declare -ax var=([0]="foo" [1]="bar")
Jesse_b
3
Lingkungan tidak dapat berisi array, AFAIK. Misalnya, export i_am_array=(foo bar); /usr/bin/env | grep i_am_arraytidak memberikan output di sini.
derobert
3
Juga: foo() { declare -p var; } ; var=(bar baz) foomemberi declare -x var="(bar baz)"konfirmasi itu diperlakukan sebagai string, bukan array
derobert

Jawaban:

19

Secara umum memanggil:

var=value cmd

Di mana cmdfungsinya tidak portabel.

Dengan bash, itu hanya berfungsi untuk variabel skalar (dan dengan x=(...)diuraikan sebagai array tetapi ditugaskan sebagai skalar) dan ada sejumlah masalah dengan pelingkupan jika Anda melakukan itu, dengan ksh93dan yash, berfungsi tetapi definisi variabel tetap setelahnya. Dengan mksh, Anda mendapatkan kesalahan sintaksis. Di shell Bourne, itu tidak bekerja sama sekali, bahkan untuk variabel skalar.

Juga perhatikan bahwa bahkan dengan variabel skalar, apakah variabel tersebut akhirnya diekspor dalam fungsi (yaitu, diteruskan ke perintah yang dijalankan) bervariasi dari shell ke shell (itu dalam bash, yash, mksh, zsh, tetapi tidak di ksh, Abu).

Ini hanya bekerja seperti yang Anda harapkan zsh. Perhatikan bahwa zshindeks array mulai dari 1.

bash-4.4$ zsh
$ a=(before value)
$ f() echo $a[1]
$ a=(temp value) f
temp
$ echo $a[1]
before
Stéphane Chazelas
sumber
12

Ini bukan hanya bug, tampaknya menjadi fitur yang tidak diterapkan tanpa rencana yang pernah jadi. Posting milis ini dari 2014 memuat ini dari penciptanya:

Untungnya, dalam bash 4.3 (patchlevel 25), Anda tidak bisa hanya -DARRAY_EXPORT dan mendapatkan variabel array impor / ekspor. Kode tidak dikompilasi, dan jika Anda memperbaikinya, itu tidak terhubung, dan jika Anda memperbaikinya, Anda berakhir dengan masalah berikut.

Itu masalah yang harus dilalui hanya untuk ini. Saya tidak punya rencana untuk mengaktifkan ekspor array.

Menarik dari repo git terbaru untuk Bash memiliki ini di variables.c:

  #  if ARRAY_EXPORT
        /* Array variables may not yet be exported. */

Menyarankan bahwa apa pun yang ada tidak lengkap.


sumber
5
Di sini, ini untuk sebuah fungsi, jadi tidak ada masalah untuk mengekspor sesuatu karena tidak ada execve()panggilan sistem yang terlibat. Lihat zshshell yang mendukung fungsi panggilan dengan larik yang sementara diatur seperti itu.
Stéphane Chazelas
@ StéphaneChazelas Tetapi lingkungan berubah (dengan menambahkan variabel baru) dan kemudian kembali ke belakang, setelah fungsi selesai (saya tentang kasus ini:) my_var=one func_bar. Bisakah kita mengatakan, itu exportmenambah lingkungan dan dengan demikian, ekspor digunakan di sini, di bawah tenda? Lihatlah jawaban saya, saya menambahkan kode demonstrasi.
MiniMax
10

Dari bagian man bashBUGS (versi bash4.3 adalah):

BUG

   Array variables may not (yet) be exported.

Kode selanjutnya menunjukkan, bahwa variabel sementara ada di lingkungan, hanya ketika fungsi sedang berjalan. Ketika fungsi selesai, variabel sementara menghilang.

### defining the "bar" function
### it pass all environment variables to the "grep" command
### and the "grep" prints the only "my_var" variable from it
bar() { env | grep my_var=; }

### calls the "bar" function with the temporary 
### variable "my_var" created and assigned.
my_var=one bar

my_var=one         ### The output. The environment contains the "my_var" variable

### checks, does the environment still have the "my_var" variable
### (It doesn't have.)
env | grep my_var=
                   ### The output is empty,
                   ### the environment doesn't contain the "my_var" variable

Informasi terkait:

MiniMax
sumber