GNU/Linux >> Linux Esercitazione >  >> Linux

Riferimenti ai nomi circolari nella funzione Bash Shell, ma non in Ksh?

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".

Correlati:come passare dall'utente root a un altro utente che ha una shell nologin?

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.

Linux
  1. Moduli Python non trovati sul terminale ma su Python Shell, Linux

  2. Mostra solo il nome della directory corrente (non il percorso completo) al prompt di bash

  3. Perché Bash è ovunque (nella maggior parte se non in tutte le distribuzioni Linux)?

  4. bash - rimuove tutte le directory (e i contenuti) ma non i file in pwd

  5. `ssh <host>` è una shell di login, ma `ssh <host> <comando>` non lo è?

Funzioni Bash

.bashrc vs .bash_profile

Shell Scripting Parte V:Funzioni in Bash

Utili comandi Bash di cui potresti non essere a conoscenza

Tutorial sulle funzioni di Bash Shell con 6 esempi pratici

Come posso annullare l'impostazione o eliminare una funzione bash?