Sto scrivendo una serie di funzioni di shell che voglio far funzionare sia in Bash che in KornShell93, ma con Bash mi imbatto in un avviso di "riferimento al nome circolare".
Questa è l'essenza del problema:
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"
Eseguirlo:
$ ksh script.sh
hello:boff
$ bash script.sh
script.sh: line 4: warning: var: circular name reference
hello:
KornShell93 fa esattamente quello che voglio, ma Bash fallisce e avverte anche della stessa cosa sulla riga 2 se il something
la variabile nello script è denominata var
invece.
Vorrei avere il var
variabile essere locale per ogni funzione, motivo per cui uso typeset
, ma a Bash non sembra piacere "dereferenziare" un nameref a una variabile con lo stesso nome del nameref stesso. Non posso usare local -n
o declare -n
poiché interromperebbe ksh
che mancano di questi, e anche se lo facessi, non risolve il problema.
L'unica soluzione che ho trovato è usare nomi di variabili univoci in ogni funzione , il che sembra piuttosto sciocco poiché sono locali.
Il manuale di Bash dice quanto segue su typeset
:
typeset
[…]
-n
Assegna a ogni nome il nameref
attributo, rendendolo un nome
riferimento a un'altra variabile. L'altra variabile è
definita dal valore di name
. Tutti i riferimenti e
assegnazioni a name
, fatta eccezione per la modifica del -n
stesso, vengono eseguiti sulla variabile a cui fa riferimento il valore del nome.
[…]
Quando viene utilizzato in una funzione, declare
e typeset
rendere ogni nome
locale, come con il local
comando, a meno che il -g
l'opzione è
fornita. Se il nome di una variabile è seguito da =value
, il valore
della variabile è impostato su value
.
È ovvio che c'è qualcosa che non capisco sui riferimenti ai nomi di Bash e sulle variabili locali delle funzioni.
Quindi, la domanda è:in questo caso, mi sfugge qualcosa sulla gestione da parte di Bash delle variabili di riferimento del nome, o si tratta di un bug/di una funzionalità errata in Bash?
Aggiorna :Attualmente sto lavorando con GNU bash, version 4.3.39(1)-release (x86_64-apple-darwin15)
così come con GNU bash, version 4.3.46(1)-release (x86_64-unknown-openbsd6.0)
. Il Bash fornito con macOS è troppo vecchio per conoscere i riferimenti ai nomi.
Aggiorna :Ancora più breve:
function bug {
typeset -n var="$1"
printf "%sn" "$var"
}
var="hello"
bug var
Risulta in bash: warning: var: circular name reference
. Il var
nella funzione dovrebbe avere un ambito diverso dal var
in ambito globale. Ciò impone una restrizione non necessaria al chiamante. La restrizione è "non ti è permesso nominare le tue variabili come vuoi, perché potrebbe esserci un conflitto di nomi con un nameref (locale) in questa funzione".
Risposta accettata:
Chet Ramey (manutentore di Bash) dice
All'inizio di quest'anno
c'è stata un'ampia discussione sui nameref su bug-bash. Ho un suggerimento ragionevole su come modificare questo comportamento,
e lo esaminerò dopo il rilascio di bash-4.4.
Nel frattempo, sto ricorrendo a offuscare leggermente i nomi delle mie variabili nameref locali, in modo che non entrino in conflitto all'interno della libreria né (si spera) con i nomi delle variabili di shell globali.
In bash
5.0, questo è sempre leggermente risolto (ma non proprio risolto). Quello che segue è il comportamento osservato:
$ 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
Questo dimostra che funziona, ma ci sono anche alcuni avvisi.
La relativa voce NEWS dice
i. A nameref name resolution loop in a function now resolves to a variable by that name in the global scope.