qual è l'equivalente zsh dell'esportazione di bash -f


24

Quindi ho iniziato a usare zsh. Mi piace tutto bene. Sembra molto bello e fluido, e il fatto che l'attuale directory di lavoro e la riga di comando attuale siano su linee diverse è bello, ma allo stesso tempo, sto notando che zshpuò essere un po 'più lento di bash, specialmente quando si stampa il testo sul schermo.

La cosa che mi è piaciuta di più è il fatto che zshera "retrocompatibile" con tutte le funzioni che ho definito nel mio .bashrc.

Una lamentela però. Tutte le funzioni funzionano perfettamente, ma non riesco a capire come funzioni il sistema di esportazione.

Ho avuto alcune di quelle .bashrcfunzioni esportate in modo da poterle usare altrove, come negli script e nei programmi esterni, con export -f.

In zsh, l'esportazione non sembra nemmeno parlarne. Si sta caricando automaticamente? Queste due cose sono uguali? Sto facendo davvero fatica a capirlo.


2
Questa è una domanda molto antica, ma voglio dire che "l'attuale directory di lavoro e la riga di comando attuale sono su linee diverse" non ha nulla a che fare con zsh. Dipende da come hai impostato il tuo prompt, tutto qui.
4ae1e1,

Risposte:


11

Le variabili d'ambiente contenenti funzioni sono un hack bash. Zsh non ha nulla di simile. Puoi fare qualcosa di simile con poche righe di codice. Le variabili di ambiente contengono stringhe; le versioni precedenti di bash, prima che Shellshock fosse scoperto, memorizzavano il codice della funzione in una variabile il cui nome è quello della funzione e il cui valore è () {seguito dal codice della funzione seguito da }. È possibile utilizzare il codice seguente per importare variabili con questa codifica e tentare di eseguirle con impostazioni simili a bash. Nota che zsh non può emulare tutte le funzionalità di bash, tutto ciò che puoi fare è avvicinarti un po '(ad es. Per $foodividere il valore ed espandere i caratteri jolly e creare array basati su 0).

bash_function_preamble='
    emulate -LR ksh
'
for name in ${(k)parameters}; do
  [[ "-$parameters[name]-" = *-export-* ]] || continue
  [[ ${(P)name} = '() {'*'}' ]] || continue
  ((! $+builtins[$name])) || continue
  functions[$name]=$bash_function_preamble${${${(P)name}#"() {"}%"}"}
done

(Come notato da Stéphane Chazelas , lo scopritore originale di Shellshock, una versione precedente di questa risposta potrebbe eseguire codice arbitrario a questo punto se la definizione della funzione fosse malformata. Questa versione non lo fa, ma ovviamente non appena si esegue un comando, potrebbe essere una funzione importata dall'ambiente.)

Le versioni post-Shellshock di bash codificano le funzioni nell'ambiente usando nomi di variabili non validi (ad es BASH_FUNC_myfunc%%.). Ciò li rende più difficili da analizzare in modo affidabile poiché zsh non fornisce un'interfaccia per estrarre tali nomi di variabili dall'ambiente.

Non consiglio di farlo. Affidarsi alle funzioni esportate negli script è una cattiva idea: crea una dipendenza invisibile nel tuo script. Se esegui mai lo script in un ambiente che non ha la tua funzione (su un altro computer, in un processo cron, dopo aver modificato i file di inizializzazione della shell, ...), lo script non funzionerà più. Invece, archivia tutte le tue funzioni in uno o più file separati (qualcosa del genere ~/lib/shell/foo.sh) e avvia i tuoi script importando le funzioni che utilizza ( . ~/lib/shell/foo.sh). In questo modo, se si modifica foo.sh, è possibile cercare facilmente quali script si basano su di esso. Se copi uno script, puoi facilmente scoprire quali file ausiliari sono necessari.

Zsh (e ksh prima) lo rende più conveniente fornendo un modo per caricare automaticamente le funzioni negli script in cui vengono utilizzate. Il vincolo è che puoi mettere solo una funzione per file. Dichiarare la funzione come caricata automaticamente e inserire la definizione della funzione in un file il cui nome è il nome della funzione. Metti questo file in una directory elencata in $fpath(che puoi configurare attraverso la FPATHvariabile d'ambiente). Nel tuo script, dichiara le funzioni caricate automaticamente con autoload -U foo.

Inoltre zsh può compilare script, per risparmiare tempo di analisi. Chiama zcompileper compilare uno script. Questo crea un file con l' .zwcestensione. Se questo file è presente, autoloadverrà caricato il file compilato anziché il codice sorgente. È possibile utilizzare la zrecompilefunzione per (ri) compilare tutte le definizioni delle funzioni in una directory.


1
Divertente come il tuo codice abbia la stessa vulnerabilità di shellshock bash(non verifica che il contenuto della variabile sia solo una definizione di funzione ed elabora qualsiasi nome di variabile come HTTP_HOSTo LC_X). Buona risposta altrimenti.
Stéphane Chazelas,

@ StéphaneChazelas Se hai intenzione di eseguire comandi con funzioni importate dall'ambiente, hai praticamente perso. Ma ho aggiornato il codice di importazione per non eseguire codice arbitrario. Non è molto utile, dal momento che bash post-shellshock non codifica le sue funzioni esportate allo stesso modo.
Gilles 'SO- smetti di essere malvagio' il

Ora hai corretto l'equivalente di CVE-2014-6271, ma probabilmente sei ancora esposto a molte vulnerabilità del tipo di CVE-2014-6277 / 6278 ... poiché stai ancora esponendo il parser zsh al codice in qualsiasi variabile compresi alcuni che sono potenzialmente sotto il controllo degli aggressori in alcuni contesti (poiché il codice in zsh -c 'functions[f]=$VAR' viene analizzato anche se la ffunzione non viene mai chiamata). La soluzione è considerare solo le variabili il cui nome segue un modello riservato come quelli $BASH_FUNC_x%%, ma come dici tu, zshnon ha API per elencarli o recuperarli. Dovresti chiamare perlper esempio.
Stéphane Chazelas il

7

Se inserisci la tua dichiarazione di funzione in .zshenv , la tua funzione sarà utilizzabile da uno script senza alcuno sforzo.


Perché hai votato in negativo la mia risposta? Spiega per favore.
Rools

Ancora in attesa di una risposta e ancora funzionante!
ruba il

Ho appena scoperto questa risposta ed è una soluzione ideale.
AFH,

Non l'ho votato a fondo. E TBH l'OP stava chiedendo di esportare cose da .bashrc, che è una cattiva idea, meglio metterlo in uno script in modo da non finire con un ambiente enorme. Ma la tua soluzione è solo una variante della stessa cattiva idea, inserisci tutti i tuoi script .zshenve rallenta ogni invocazione di zsh analizzando un sacco di codice che non viene mai utilizzato. Inoltre non è la stessa cosa dell'esportazione di una funzione, proprio come una variabile esportata, una funzione esportata è disponibile solo per i processi figlio. Considerando che le cose che hai inserito .zshenvsono disponibili per ogni zsh.
Metamorfico

Infine, se fai affidamento sul codice personale inserito nel tuo .zshenv, allora tutti i tuoi script saranno totalmente non portatili. Normalmente gli script potrebbero dipendere l'uno dall'altro, il che va bene, li distribuisci insieme. Ma se dipendono dall'avere funzioni speciali .zshenv, nessuno vorrà usarle, o dovrebbero essere invocate con una speciale ZDOTDIR, impedendo che le tue .zshenvvengano eseguite. Sarebbe un dolore.
Metamorfico
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.