comando eval in Bash e suoi usi tipici


165

Dopo aver letto le pagine man di bash e rispetto a questo post .

Ho ancora problemi a capire esattamente cosa fa il evalcomando e quali sarebbero i suoi usi tipici. Ad esempio se lo facciamo:

bash$ set -- one two three  # sets $1 $2 $3
bash$ echo $1
one
bash$ n=1
bash$ echo ${$n}       ## First attempt to echo $1 using brackets fails
bash: ${$n}: bad substitution
bash$ echo $($n)       ## Second attempt to echo $1 using parentheses fails
bash: 1: command not found
bash$ eval echo \${$n} ## Third attempt to echo $1 using 'eval' succeeds
one

Cosa sta succedendo esattamente qui e in che modo il simbolo del dollaro e la barra rovesciata si collegano al problema?


1
Per la cronaca, il secondo tentativo funziona. $($n)viene eseguito $nin una subshell. Tenta di eseguire il comando 1che non esiste.
Martin Wickman,

1
@MartinWickman Ma alla echo $1fine è necessario eseguire , no 1. Non penso che si possa fare usando i subshells.
Hari Menon,


1
@ Raze2dust: non credo che stesse suggerendo che potesse essere eseguito con subshells, ma piuttosto spiegando perché il 5 ° comando elencato nel PO non funzionava.
jedwards,

Risposte:


196

evalaccetta una stringa come argomento e la valuta come se fosse stata digitata quella stringa su una riga di comando. (Se passi diversi argomenti, vengono prima uniti con degli spazi tra loro.)

${$n}è un errore di sintassi in bash. All'interno delle parentesi graffe, puoi avere solo un nome variabile, con alcuni possibili prefissi e suffissi, ma non puoi avere sintassi bash arbitraria e in particolare non puoi usare l'espansione variabile. C'è un modo di dire "il valore della variabile il cui nome è in questa variabile", sebbene:

echo ${!n}
one

$(…)esegue il comando specificato tra parentesi in una subshell (ovvero in un processo separato che eredita tutte le impostazioni come i valori delle variabili dalla shell corrente) e ne raccoglie l'output. Quindi echo $($n)viene eseguito $ncome comando shell e visualizza il suo output. Poiché $nvaluta 1, $($n)tenta di eseguire il comando 1, che non esiste.

eval echo \${$n}esegue i parametri passati a eval. Dopo l'espansione, i parametri sono echoe ${1}. Quindi eval echo \${$n}esegue il comando echo ${1}.

Nota che la maggior parte del tempo, è necessario utilizzare le virgolette doppie intorno sostituzioni variabili e sostituzioni di comando (cioè in qualsiasi momento ci sia una $): "$foo", "$(foo)". Metti sempre le virgolette doppie attorno alle sostituzioni di variabili e comandi , a meno che tu non sappia che devi lasciarle fuori. Senza le doppie virgolette, la shell esegue la divisione dei campi (ovvero divide il valore della variabile o l'output del comando in parole separate) e quindi tratta ogni parola come un modello jolly. Per esempio:

$ ls
file1 file2 otherfile
$ set -- 'f* *'
$ echo "$1"
f* *
$ echo $1
file1 file2 file1 file2 otherfile
$ n=1
$ eval echo \${$n}
file1 file2 file1 file2 otherfile
$eval echo \"\${$n}\"
f* *
$ echo "${!n}"
f* *

evalnon viene usato molto spesso. In alcune shell, l'uso più comune è quello di ottenere il valore di una variabile il cui nome non è noto fino al runtime. In bash, questo non è necessario grazie alla ${!VAR}sintassi. evalè ancora utile quando è necessario costruire un comando più lungo contenente operatori, parole riservate, ecc.


Per quanto riguarda il mio commento sopra, quanti "passaggi" fa l'Eval?
kstratis,

@ Konos5 Quale commento? evalriceve una stringa (che può essere essa stessa il risultato dell'analisi e della valutazione) e la interpreta come uno snippet di codice.
Gilles 'SO- smetti di essere malvagio' il

Sotto la risposta di Raze2dust ho lasciato un commento. Tendo ora a credere che eval sia usato principalmente per scopi di dereferenziazione. Se digito eval echo \ $ {$ n} ne ottengo uno. Tuttavia, se digito echo \ $ {$ n} ottengo \ $ {1}. Credo che ciò stia accadendo a causa dell'analisi "a due passaggi" di eval. Ora mi chiedo cosa succederebbe se dovessi triplicare la dereferenza usando una dichiarazione i = n aggiuntiva. In questo caso, secondo Raze2dust, devo solo aggiungere un ulteriore giudizio. Credo comunque che dovrebbe esserci un modo migliore ... (può essere facilmente ingombra)
kstratis,

@ Konos5 Non vorrei usare eval eval. Non ricordo di aver mai sentito il bisogno. Se davvero bisogno di due evalpassaggi, utilizzare una variabile temporanea, sarà più facile per eseguire il debug: eval tmp="\${$i}"; eval x="\${$tmp}".
Gilles 'SO- smetti di essere malvagio' il

1
@ Konos5 "Analizzato due volte" è leggermente fuorviante. Alcune persone potrebbero essere portate a crederci a causa della difficoltà di specificare un argomento letterale in stringa in Bash che è protetto da varie espansioni. evalprende semplicemente il codice in una stringa e lo valuta secondo le normali regole. Tecnicamente, non è nemmeno corretto, perché ci sono alcuni casi angolari in cui Bash modifica l'analisi per non eseguire nemmeno espansioni agli argomenti di eval - ma è un boccone molto oscuro che dubito che qualcuno sappia.
ormaaj,

39

Pensa semplicemente a eval come a "valutare la tua espressione un'altra volta prima dell'esecuzione"

eval echo \${$n}diventa echo $1dopo il primo round di valutazione. Tre modifiche da notare:

  • È \$diventato $(La barra rovesciata è necessaria, altrimenti prova a valutare ${$n}, il che significa una variabile denominata {$n}, che non è consentita)
  • $n è stato valutato a 1
  • Il evalscomparso

Nel secondo round, è fondamentalmente echo $1che può essere eseguito direttamente.

Quindi eval <some command>prima valuterò <some command>(per valutazione qui intendo sostituire le variabili, sostituire i caratteri di escape con quelli corretti, ecc.), Quindi eseguire nuovamente l'espressione risultante.

evalviene utilizzato quando si desidera creare dinamicamente variabili o leggere output da programmi specificamente progettati per essere letti in questo modo. Vedi http://mywiki.wooledge.org/BashFAQ/048 per esempi. Il collegamento contiene anche alcuni modi tipici in cui evalviene utilizzato e i rischi ad esso associati.


3
Come nota per il primo punto elenco, la ${VAR}sintassi è consentita e preferita quando c'è qualche ambiguità (fa $VAR == $V, seguito ARo $VAR == $VAseguito da R). ${VAR}è equivalente a $VAR. In realtà, $nnon è consentito il nome della variabile .
jedwards,

2
eval eval echo \\\${\${$i}}farà una triplice dereferenza. Non sono sicuro se esiste un modo più semplice per farlo. Inoltre, \${$n}funziona benissimo (stampa one) sulla mia macchina ..
Hari Menon,

2
@ echo \\\${\${$i}}Stampe Konos5 \${${n}}. eval echo \\\${\${$i}}è equivalente a echo \${${n}}`` and prints $ {1} . eval eval echo \\\ $ {\ $ {$ i}} `è equivalente eval echo ${1}e stampa one.
Gilles 'SO- smetti di essere malvagio' il

2
@ Konos5 Pensa seguendo le stesse linee - Il primo ` escapes the second one, and the third `sfugge al $dopo. Così diventa \${${n}}dopo un giro di valutazione
Hari Menon,

2
@ Konos5 Da sinistra a destra è il modo giusto di pensare per l'analisi del preventivo e della barra rovesciata. \\ Dare prima una barra rovesciata. Quindi \$cedere un dollaro. E così via.
Gilles 'SO- smetti di essere malvagio' il

25

Nella mia esperienza, un uso "tipico" di eval è per eseguire comandi che generano comandi di shell per impostare variabili di ambiente.

Forse hai un sistema che utilizza una raccolta di variabili d'ambiente e hai uno script o un programma che determina quali dovrebbero essere impostati e i loro valori. Ogni volta che esegui uno script o un programma, viene eseguito in un processo biforcato, quindi tutto ciò che fa direttamente alle variabili di ambiente viene perso quando esce. Ma quello script o programma può inviare i comandi di esportazione a stdout.

Senza eval, è necessario reindirizzare stdout a un file temporaneo, eseguire il sorgente del file temporaneo e quindi eliminarlo. Con eval, puoi semplicemente:

eval "$(script-or-program)"

Nota che le virgolette sono importanti. Prendi questo esempio (inventato):

# activate.sh
echo 'I got activated!'

# test.py
print("export foo=bar/baz/womp")
print(". activate.sh")

$ eval $(python test.py)
bash: export: `.': not a valid identifier
bash: export: `activate.sh': not a valid identifier
$ eval "$(python test.py)"
I got activated!

hai qualche esempio di strumenti comuni che lo fanno? Lo strumento stesso ha un mezzo per produrre una serie di comandi di shell che possono essere passati ad eval?
Joakim Erdfelt,

@Joakim Non conosco alcuno strumento open source che lo faccia, ma è stato usato in alcuni script privati ​​di aziende in cui ho lavorato. Ho appena iniziato a usare di nuovo questa tecnica con xampp. I file .conf di Apache espandono le variabili di ambiente scritte ${varname}. Trovo conveniente usare file .conf identici su più server diversi con solo alcune cose parametrizzate da variabili d'ambiente. Ho modificato / opt / lampp / xampp (che avvia apache) per fare questo tipo di valutazione con uno script che fa capolino sul sistema e genera exportistruzioni bash per definire le variabili per i file .conf.
sootsnoot,

@Joakim L'alternativa sarebbe quella di avere uno script per generare ciascuno dei file .conf interessati da un modello, basato sullo stesso poking. Una cosa che mi piace di più della mia strada è che l'avvio di apache senza passare per / opt / lampp / xampp non utilizza script di output non aggiornati, ma piuttosto non si avvia perché le variabili di ambiente non si espandono e creano direttive non valide.
sootsnoot,

@Anthony Sottile Vedo che hai modificato la risposta per aggiungere virgolette intorno a $ (script o programma), dicendo che erano importanti quando si eseguivano più comandi. Potete per favore fornire un esempio: quanto segue funziona bene con comandi separati da punti e virgola nello stdout di foo.sh: echo '#! / Bin / bash'> foo.sh; echo 'echo "echo -na; echo -nb; echo -n c"' >> foo.sh; chmod 755 foo.sh; eval $ (./ foo.sh). Questo produce abc su stdout. L'esecuzione di ./foo.sh produce: echo -na; echo -nb; echo -nc
sootsnoot

1
Per un esempio di uno strumento comune che utilizza eval, vedere pyenv . pyenv ti consente di passare facilmente tra più versioni di Python. Hai messo eval "$(pyenv init -)"nel vostro .bash_profilefile di configurazione (o simili) shell. Costruisce un piccolo script di shell, quindi lo valuta nella shell corrente.
Jerry101,

10

L'istruzione eval dice alla shell di prendere gli argomenti di eval come comando ed eseguirli attraverso la riga di comando. È utile in una situazione come di seguito:

Nel tuo script se stai definendo un comando in una variabile e successivamente vuoi usare quel comando, allora dovresti usare eval:

/home/user1 > a="ls | more"
/home/user1 > $a
bash: command not found: ls | more
/home/user1 > # Above command didn't work as ls tried to list file with name pipe (|) and more. But these files are not there
/home/user1 > eval $a
file.txt
mailids
remote_cmd.sh
sample.txt
tmp
/home/user1 >

4

Aggiornamento: alcuni dicono che si dovrebbe -non usare mai eval. Non sono d'accordo. Penso che il rischio insorga quando si può passare a un input corrotto eval. Tuttavia ci sono molte situazioni comuni in cui ciò non rappresenta un rischio, e quindi vale la pena sapere come utilizzare eval in ogni caso. Questa risposta allo stackover spiega i rischi di eval e le alternative a eval. In definitiva spetta all'utente determinare se / quando eval è sicuro ed efficiente da usare.


L' evalistruzione bash consente di eseguire righe di codice calcolate o acquisite dallo script bash.

Forse l'esempio più semplice sarebbe un programma bash che apre un altro script bash come file di testo, legge ogni riga di testo e lo usa evalper eseguirli in ordine. Questo è essenzialmente lo stesso comportamento dell'istruzione bash source, che è ciò che si vorrebbe usare, a meno che non fosse necessario eseguire un qualche tipo di trasformazione (ad esempio filtro o sostituzione) sul contenuto dello script importato.

Raramente ne ho avuto bisogno eval, ma ho trovato utile leggere o scrivere variabili i cui nomi erano contenuti in stringhe assegnate ad altre variabili. Ad esempio, per eseguire azioni su insiemi di variabili, mantenendo l'ingombro del codice ridotto ed evitando la ridondanza.

evalè concettualmente semplice. Tuttavia, la sintassi rigorosa del linguaggio bash e l'ordine di analisi dell'interprete bash possono essere sfumati e rendere evalcriptici e difficili da usare o da capire. Ecco gli elementi essenziali:

  1. L'argomento passato a evalè un'espressione stringa calcolata in fase di esecuzione. evaleseguirà il risultato finale analizzato del suo argomento come una riga di codice effettiva nel tuo script.

  2. La sintassi e l'ordine di analisi sono rigorosi. Se il risultato non è una riga eseguibile di codice bash, nell'ambito del tuo script, il programma si arresterà in modo anomalo evalsull'istruzione mentre tenta di eseguire la spazzatura.

  3. Durante il test è possibile sostituire l' evalistruzione con echoe vedere cosa viene visualizzato. Se si tratta di un codice legittimo nel contesto corrente, eseguirlo evalfunzionerà.


I seguenti esempi possono aiutare a chiarire come funziona eval ...

Esempio 1:

eval l'istruzione davanti al codice "normale" è un NOP

$ eval a=b
$ eval echo $a
b

Nell'esempio sopra, le prime evalaffermazioni non hanno scopo e possono essere eliminate. evalè inutile nella prima riga perché non c'è alcun aspetto dinamico nel codice, cioè è già analizzato nelle righe finali del codice bash, quindi sarebbe identico a una normale istruzione di codice nello script bash. Anche il 2 ° evalè inutile, perché, sebbene ci sia una fase di analisi che converte $anella sua stringa letterale equivalente, non vi è alcuna indiretta (ad esempio nessun riferimento tramite il valore di stringa di un vero nome bash o variabile di script con bash), quindi si comporterebbe in modo identico come una riga di codice senza evalprefisso.



Esempio 2:

Eseguire l'assegnazione var utilizzando i nomi var passati come valori stringa.

$ key="mykey"
$ val="myval"
$ eval $key=$val
$ echo $mykey
myval

Se dovessi echo $key=$val, l'output sarebbe:

mykey=myval

Questo , essendo il risultato finale dell'analisi delle stringhe, è ciò che verrà eseguito da eval, quindi il risultato dell'istruzione echo alla fine ...



Esempio 3:

Aggiunta di ulteriori riferimenti indiretti all'esempio 2

$ keyA="keyB"
$ valA="valB"
$ keyB="that"
$ valB="amazing"
$ eval eval \$$keyA=\$$valA
$ echo $that
amazing

Quanto sopra è un po 'più complicato dell'esempio precedente, basandosi maggiormente sull'ordine di analisi e sulle peculiarità di bash. La evalriga verrebbe approssimativamente analizzata internamente nel seguente ordine (nota che le seguenti affermazioni sono pseudocodice, non codice reale, solo per tentare di mostrare come l'istruzione verrebbe suddivisa in passaggi internamente per arrivare al risultato finale) .

 eval eval \$$keyA=\$$valA  # substitution of $keyA and $valA by interpreter
 eval eval \$keyB=\$valB    # convert '$' + name-strings to real vars by eval
 eval $keyB=$valB           # substitution of $keyB and $valB by interpreter
 eval that=amazing          # execute string literal 'that=amazing' by eval

Se l'ordine di analisi ipotizzato non spiega cosa sta facendo abbastanza eval, il terzo esempio può descrivere l'analisi in modo più dettagliato per aiutare a chiarire cosa sta succedendo.



Esempio 4:

Scopri se i var, i cui nomi sono contenuti nelle stringhe, contengono essi stessi valori di stringa.

a="User-provided"
b="Another user-provided optional value"
c=""

myvarname_a="a"
myvarname_b="b"
myvarname_c="c"

for varname in "myvarname_a" "myvarname_b" "myvarname_c"; do
    eval varval=\$$varname
    if [ -z "$varval" ]; then
        read -p "$varname? " $varname
    fi
done

Nella prima iterazione:

varname="myvarname_a"

Bash analizza l'argomento evale lo evalvede letteralmente in fase di esecuzione:

eval varval=\$$myvarname_a

Il seguente pseudocodice tenta di illustrare come bash interpreta la riga sopra del codice reale , per arrivare al valore finale eseguito da eval. (le seguenti righe descrittive, non esatto codice bash):

1. eval varval="\$" + "$varname"      # This substitution resolved in eval statement
2. .................. "$myvarname_a"  # $myvarname_a previously resolved by for-loop
3. .................. "a"             # ... to this value
4. eval "varval=$a"                   # This requires one more parsing step
5. eval varval="User-provided"        # Final result of parsing (eval executes this)

Una volta eseguito tutto l'analisi, il risultato è ciò che viene eseguito e il suo effetto è evidente, dimostrando che non c'è nulla di particolarmente misterioso in se evalstesso e la complessità sta nell'analisi del suo argomento.

varval="User-provided"

Il codice rimanente nell'esempio sopra verifica semplicemente se il valore assegnato a $ varval è null e, in tal caso, richiede all'utente di fornire un valore.


3

Inizialmente non avevo mai intenzionalmente imparato a usare eval, perché la maggior parte delle persone consiglierà di starne alla larga come la peste. Tuttavia, di recente ho scoperto un caso d'uso che mi ha reso facepalm per non averlo riconosciuto prima.

Se si dispone di processi cron che si desidera eseguire in modo interattivo per il test, è possibile visualizzare il contenuto del file con cat e copiare e incollare il processo cron per eseguirlo. Sfortunatamente, questo implica toccare il mouse, che è un peccato nel mio libro.

Supponiamo che tu abbia un lavoro cron su /etc/cron.d/repeatme con i contenuti:

*/10 * * * * root program arg1 arg2

Non puoi eseguirlo come uno script con tutta la spazzatura di fronte, ma possiamo usare il taglio per sbarazzarci di tutta la spazzatura, avvolgerlo in una subshell ed eseguire la stringa con eval

eval $( cut -d ' ' -f 6- /etc/cron.d/repeatme)

Il comando cut stampa solo il sesto campo del file, delimitato da spazi. Eval quindi esegue quel comando.

Ho usato un lavoro cron qui come esempio, ma il concetto è quello di formattare il testo da stdout e quindi valutare quel testo.

L'uso di eval in questo caso non è insicuro, perché sappiamo esattamente cosa valuteremo prima.


2

Di recente ho dovuto usare evalper forzare più espansioni di controventi da valutare nell'ordine di cui avevo bisogno. Bash fa più espansioni di parentesi graffe da sinistra a destra, quindi

xargs -I_ cat _/{11..15}/{8..5}.jpg

si espande a

xargs -I_ cat _/11/8.jpg _/11/7.jpg _/11/6.jpg _/11/5.jpg _/12/8.jpg _/12/7.jpg _/12/6.jpg _/12/5.jpg _/13/8.jpg _/13/7.jpg _/13/6.jpg _/13/5.jpg _/14/8.jpg _/14/7.jpg _/14/6.jpg _/14/5.jpg _/15/8.jpg _/15/7.jpg _/15/6.jpg _/15/5.jpg

ma avevo bisogno che la seconda espansione della parentesi graffa venisse eseguita per prima, cedendo

xargs -I_ cat _/11/8.jpg _/12/8.jpg _/13/8.jpg _/14/8.jpg _/15/8.jpg _/11/7.jpg _/12/7.jpg _/13/7.jpg _/14/7.jpg _/15/7.jpg _/11/6.jpg _/12/6.jpg _/13/6.jpg _/14/6.jpg _/15/6.jpg _/11/5.jpg _/12/5.jpg _/13/5.jpg _/14/5.jpg _/15/5.jpg

Il meglio che ho potuto inventarmi è stato

xargs -I_ cat $(eval echo _/'{11..15}'/{8..5}.jpg)

Questo funziona perché le virgolette singole proteggono il primo set di parentesi graffe dall'espansione durante l'analisi della evalriga di comando, lasciandole espandere dalla subshell invocata da eval.

Potrebbe esserci qualche astuzia che prevede espansioni di parentesi graffe nidificate che consente che ciò avvenga in un solo passaggio, ma se c'è sono troppo vecchio e stupido per vederlo.


1

Hai chiesto informazioni sugli usi tipici.

Una lamentela comune sullo scripting della shell è che (presumibilmente) non è possibile passare per riferimento per ripristinare i valori dalle funzioni.

Ma in realtà, tramite "eval", puoi passare per riferimento. Il chiamante può restituire un elenco di assegnazioni di variabili che devono essere valutate dal chiamante. Viene passato per riferimento perché al chiamante è consentito specificare il nome (i) delle variabili di risultato - vedere l'esempio seguente. I risultati dell'errore possono essere restituiti con nomi standard come errno ed errstr.

Ecco un esempio di passaggio per riferimento in bash:

#!/bin/bash
isint()
{
    re='^[-]?[0-9]+$'
    [[ $1 =~ $re ]]
}

#args 1: name of result variable, 2: first addend, 3: second addend 
iadd()
{
    if isint ${2} && isint ${3} ; then
        echo "$1=$((${2}+${3}));errno=0"
        return 0
    else
        echo "errstr=\"Error: non-integer argument to iadd $*\" ; errno=329"
        return 1
    fi
}

var=1
echo "[1] var=$var"

eval $(iadd var A B)
if [[ $errno -ne 0 ]]; then
    echo "errstr=$errstr"
    echo "errno=$errno"
fi
echo "[2] var=$var (unchanged after error)"

eval $(iadd var $var 1)
if [[ $errno -ne 0 ]]; then
    echo "errstr=$errstr"
    echo "errno=$errno"
fi  
echo "[3] var=$var (successfully changed)"

L'output è simile al seguente:

[1] var=1
errstr=Error: non-integer argument to iadd var A B
errno=329
[2] var=1 (unchanged after error)
[3] var=2 (successfully changed)

C'è una larghezza di banda quasi illimitata nell'output del testo! E ci sono più possibilità se vengono utilizzate più righe di output: ad esempio, la prima riga potrebbe essere utilizzata per assegnazioni di variabili, la seconda per "flusso di pensiero" continuo, ma questo va oltre lo scopo di questo post.


dire che ci sono "più possibilità" è poco, banale e ridondante per non dire altro.
dotbit

0

Mi piace la risposta "valutare la tua espressione un'altra volta prima dell'esecuzione" e vorrei chiarire con un altro esempio.

var="\"par1 par2\""
echo $var # prints nicely "par1 par2"

function cntpars() {
  echo "  > Count: $#"
  echo "  > Pars : $*"
  echo "  > par1 : $1"
  echo "  > par2 : $2"

  if [[ $# = 1 && $1 = "par1 par2" ]]; then
    echo "  > PASS"
  else
    echo "  > FAIL"
    return 1
  fi
}

# Option 1: Will Pass
echo "eval \"cntpars \$var\""
eval "cntpars $var"

# Option 2: Will Fail, with curious results
echo "cntpars \$var"
cntpars $var

I risultati curiosi nell'opzione 2 sono che avremmo passato 2 parametri come segue:

  • Primo parametro: "value
  • Secondo parametro: content"

Com'è intuitivo questo contatore? L'ulteriore evalrisolverà ciò.

Adattato da https://stackoverflow.com/a/40646371/744133


0

Nella domanda:

who | grep $(tty | sed s:/dev/::)

genera errori sostenendo che i file a e tty non esistono. Ho capito che ciò significa che tty non viene interpretato prima dell'esecuzione di grep, ma invece che bash ha passato tty come parametro a grep, che lo ha interpretato come un nome di file.

Esiste anche una situazione di reindirizzamento nidificato, che dovrebbe essere gestita da parentesi corrispondenti che dovrebbero specificare un processo figlio, ma bash è primariamente un separatore di parole, creando parametri da inviare a un programma, quindi le parentesi non vengono prima associate, ma interpretate come visto.

Sono diventato specifico con grep e ho specificato il file come parametro invece di usare una pipe. Ho anche semplificato il comando di base, passando l'output di un comando come file, in modo che le tubazioni di I / o non venissero nidificate:

grep $(tty | sed s:/dev/::) <(who)

funziona bene.

who | grep $(echo pts/3)

non è proprio desiderato, ma elimina il tubo nidificato e funziona anche bene.

In conclusione, a bash non sembra piacere il piercing annidato. È importante capire che bash non è un programma new-wave scritto in modo ricorsivo. Invece, bash è un vecchio programma 1,2,3, che è stato aggiunto con funzionalità. Ai fini di garantire la retrocompatibilità, il modo di interpretare iniziale non è mai stato modificato. Se bash fosse riscritto per abbinare prima le parentesi, quanti bug verrebbero introdotti in quanti programmi bash? Molti programmatori adorano essere criptici.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.