GNU/Linux >> Znalost Linux >  >> Linux

Kruhové odkazy na názvy ve funkci Bash Shell, ale ne v Ksh?

Píšu sadu funkcí shellu, které chci, aby fungovaly jak v Bash, tak v KornShell93, ale s Bash narážím na varování „kruhový název“.

Toto je podstata problému:

function set_it {
    typeset -n var="$1"

    var="hello:$var"
}

function call_it {
    typeset -n var="$1"

    set_it var
}

something="boff"
call_it something
echo "$something"

Spuštění:

$ ksh script.sh
hello:boff

$ bash script.sh
script.sh: line 4: warning: var: circular name reference
hello:

KornShell93 dělá přesně to, co chci, ale Bash selže a také varuje před stejnou věcí na řádku 2, pokud something proměnná ve skriptu se jmenuje var místo toho.

Chtěl bych mít var proměnná být lokální pro každou funkci, proto používám typeset , ale nezdá se, že by Bash rád „odkazoval“ nameref na proměnnou se stejným názvem jako samotný nameref. Nemohu použít local -n nebo declare -n protože by se zlomil v ksh který je postrádá, a i kdybych to udělal, problém to neřeší.

Jediné řešení, které jsem našel, je použít v každé funkci jedinečné názvy proměnných , což vypadá poněkud hloupě, protože jsou místní.

Bash manuál říká následující o typeset :

typeset […]

-n Každému názvu dejte nameref atribut, což z něj udělá
odkaz na jinou proměnnou. Tato další proměnná je
definována hodnotou name . Všechny odkazy a
přiřazení k name , kromě změny -n
samotný atribut, se provádějí na proměnné, na kterou odkazuje hodnota názvu.

[…]

Při použití ve funkci declare a typeset udělejte každý název
místní, jako u local příkaz, pokud není -g možnost je
dodávána. Pokud za názvem proměnné následuje =value ,
hodnota proměnné je nastavena na value .

Je zřejmé, že na Bashových odkazech na jména a funkčních lokálních proměnných je něco, čemu nerozumím.

Otázka tedy zní:Chybí mi v tomto případě něco o tom, jak Bash zachází s proměnnými reference názvu, nebo je to chyba/chybná funkce v Bash?

Aktualizovat :Momentálně pracuji s GNU bash, version 4.3.39(1)-release (x86_64-apple-darwin15) stejně jako s GNU bash, version 4.3.46(1)-release (x86_64-unknown-openbsd6.0) . Bash dodávaný s macOS je příliš starý na to, aby vůbec věděl o odkazech na názvy.

Aktualizovat :Ještě kratší:

function bug {
    typeset -n var="$1"
    printf "%sn" "$var"
}

var="hello"
bug var

Výsledky v bash: warning: var: circular name reference . var ve funkci by měla mít jiný rozsah z var v celosvětovém měřítku. To ukládá volajícímu zbytečné omezení. Omezení zní:„nemáte povoleno pojmenovávat své proměnné, jak chcete, protože v této funkci může dojít ke střetu názvu s (místním) nameref.“

Související:Jak přepnout z uživatele root na jiného uživatele, který má nologin shell?

Přijatá odpověď:

Chet Ramey (správce Bash) říká

Na začátku tohoto roku proběhla rozsáhlá diskuse o namerefs na bug-bash. Mám rozumný návrh, jak toto chování změnit,
a po vydání bash-4.4 se na něj podívám.

Mezitím se uchyluji k mírnému zamlžení názvů mých lokálních proměnných nameref, aby se nekolidovaly v rámci knihovny ani (doufejme) s názvy globálních proměnných shellu.

V bash 5.0, toto je vždy tak trochu opraveno (ale ne ve skutečnosti opraveno). Toto je pozorované chování:

$ foo () { typeset -n var="$1"; echo "$var"; }
$ var=hello
$ foo var
bash: typeset: warning: var: circular name reference
bash: warning: var: circular name reference
bash: warning: var: circular name reference
hello

To ukazuje, že to funguje, ale je zde také několik varování.

Příslušný záznam NEWS říká

i. A nameref name resolution loop in a function now resolves to a variable by
that name in the global scope.

Linux
  1. Přizpůsobení prostředí Bash

  2. Rozdíl mezi proměnnými Shell, které se exportují, a těmi, které nejsou v Bash?

  3. Funkce v proměnných Shell?

  1. Jakýkoli způsob, jak ukončit bash skript, ale ne opustit terminál

  2. Na příkazovém řádku bash zobrazit pouze název aktuálního adresáře (ne úplnou cestu).

  3. Proč je Bash všude (ve většině, ne-li ve všech distribucích Linuxu)?

  1. Moduly Pythonu nebyly nalezeny přes terminál, ale na python shell, Linux

  2. bash - odstraní všechny adresáře (a obsah), ale ne soubory v pwd

  3. Povolit SCP, ale ne skutečné přihlášení pomocí SSH