Możliwy błąd w Bash ?: foo () {echo „$ {var [0]}”; }; var = (bar baz) foo

22

System operacyjny : Ubuntu 16.04.3

Powłoka : Bash 4.3.48


Wiem, że można tymczasowo zmienić zawartość zmiennej jak w var=value command, prawdopodobnie jest IFS= read -r varto najbardziej znaczący przypadek.

I dzięki wiki Grega , rozumiem też:

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

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

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

To, co wymyka się mojemu zrozumieniu, to:

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

O ile mi wiadomo (i zgodnie z logiką poprzednich przykładów), powinien drukować bar, a nie (bar baz).

Czy to mi się tylko zdarza? Czy to jest zamierzone zachowanie i czegoś mi brakuje? Czy to błąd?

nxnev
źródło
3
Być może ma to coś wspólnego z tym, że bash nie obsługuje tablic jako zmiennych środowiskowych?
Jesse_b
3
@Jesse_b Może. Chociaż po uruchomieniu export var=(foo bar); echo "${var[0]}"drukuje foo, nie (foo bar).
nxnev
1
Dziwne, to też działało dla mnie. I użycie exportgo pokazuje:declare -ax var=([0]="foo" [1]="bar")
Jesse_b
3
Środowisko nie może zawierać tablic, AFAIK. Np. Nie export i_am_array=(foo bar); /usr/bin/env | grep i_am_arraydaje tutaj żadnego wyniku.
derobert
3
Ponadto: foo() { declare -p var; } ; var=(bar baz) foodaje declare -x var="(bar baz)"potwierdzenie, że jest traktowany jako ciąg, a nie tablica
derobert,

Odpowiedzi:

19

Ogólnie dzwoniąc:

var=value cmd

gdzie cmdfunkcja nie jest przenośna.

Z bash, to działa tylko dla zmiennych skalarnych (i x=(...)parsowanych jako tablica, ale przypisanych jako skalar) i istnieje szereg problemów z zasięgiem, jeśli to zrobisz, z ksh93i yash, to działa, ale definicja zmiennej pozostaje później. Za pomocą mkshpojawia się błąd składniowy. W powłoce Bourne'a w ogóle nie działało, nawet w przypadku zmiennych skalarnych.

Zauważ również, że nawet w przypadku zmiennych skalarnych, to, czy zmienna zostanie ostatecznie wyeksportowana w ramach funkcji (to znaczy przekazana do wykonywanych poleceń) różni się w zależności od powłoki (w bash, yash, mksh, zsh, ale nie w ksh, popiół).

Działa tylko tak, jak można się spodziewać zsh. Zauważ, że zshindeksy tablic zaczynają się od 1.

bash-4.4$ zsh
$ a=(before value)
$ f() echo $a[1]
$ a=(temp value) f
temp
$ echo $a[1]
before
Stéphane Chazelas
źródło
12

To nie tylko błąd, ale wydaje się, że jest to niezaimplementowana funkcja bez żadnych planów. Ten post z listy mailingowej z 2014 roku ma od twórcy:

Na szczęście w bash 4.3 (patchlevel 25) nie można po prostu -DARRAY_EXPORT i uzyskać import / eksport zmiennych tablicowych. Kod się nie kompiluje, a jeśli to naprawisz, nie będzie się łączył, a jeśli to naprawisz, powstanie następujący problem.

To mnóstwo kłopotów, aby przez to przejść. Nie mam żadnych planów włączenia eksportu macierzy.

Korzystając z najnowszego repozytorium git dla Bash, można to zrobić w variables.c:

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

Sugerowanie, że cokolwiek tam jest, nie jest kompletne.


źródło
5
Tutaj jest dla funkcji, więc nie ma mowy o eksportowaniu czegokolwiek, ponieważ nie execve()jest zaangażowane wywołanie systemowe. Poszukaj zshpowłoki obsługującej funkcje wywołujące tymczasowo ustawioną tablicę.
Stéphane Chazelas,
@ StéphaneChazelas Ale środowisko zmienia się (dodając nową zmienną), a następnie wraca do tyłu, po zakończeniu funkcji (jestem o tym przypadku my_var=one func_bar:). Czy możemy powiedzieć, że exportjest to korzystne dla środowiska, a zatem eksport jest wykorzystywany tutaj, pod maską? Spójrz na moją odpowiedź, dodałem kod demonstracyjny.
MiniMax,
10

Z man bashsekcji BŁĘDY (wersja bash4.3):

ROBAKI

   Array variables may not (yet) be exported.

Następny kod pokazuje, że zmienna tymczasowa istnieje w środowisku, tylko gdy funkcja jest uruchomiona. Po zakończeniu funkcji zmienna tymczasowa znika.

### 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

Powiązana informacja:

MiniMax
źródło