Elenca gli elementi con spazi in zsh


10

Ho studiato zsh scripting per tutte le 2 ore a questo punto e ho colpito un muro. Voglio passare attraverso un elenco di file che possono contenere spazi. Sono aperto ad approcci completamente diversi dal seguente esempio, purché siano zsh poiché zsh è ciò che sto studiando, non il compito che sto provando a scrivere.

files=(`ls`)
for f in $files; do
    print $f
done

Ovviamente non sto solo ricreando ls, voglio solo $fcatturare l'intero nome del file ogni iterazione del ciclo.

Risposte:


12

Innanzitutto, suppongo che l'uso di lssia solo un esempio. Non è possibile analizzare l'output di lsin nessuna shell, perché è ambiguo. Leggi Perché non dovresti analizzare l'output di ls (1) se questa è una novità per te. In qualsiasi shell, per ottenere un elenco di file, utilizzare i caratteri jolly, ad es files=(*).

In zsh, come in altre shell, il risultato della sostituzione del comando è diviso in parole in caratteri di spazi bianchi (più precisamente, in base al valore di IFS). (A differenza di altre shell, il risultato della sostituzione del comando non è soggetto a globbing in zsh.) Quindi se l'output del lscomando è

hello world
wibble

quindi files=($(ls))imposta la filesmatrice per contenere 3 elementi: hello, worlde wibble.

Se la sostituzione del comando è tra virgolette, non viene eseguita alcuna divisione. È possibile eseguire una suddivisione personalizzata con flag di espansione dei parametri . Utilizzare il @flag per indicare che il risultato della divisione deve essere un array (stranamente, è necessario mantenere l'espansione tra virgolette doppie, vale a dire "${(@)…}", anche se la stringa tra virgolette si espanderà in più parole). Per dividere, utilizzare la sbandiera, ad esempio "${(@s:,:)…}"per dividere in virgole; la fbandiera si divide solo a newline.

files=("${(@f)$(ls)}")

Si noti che il modo corretto di scorrere su un array in generale è for f in $files[@], come $filesrimuovere gli elementi vuoti (qui, non importa perché gli elementi non saranno vuoti).

print $finterpreta $fun interruttore se inizia con a -ed espande le barre rovesciate in $f. Utilizzare print -r -- $fo print -rn -- $fse non si desidera aggiungere una nuova riga dopo la stringa.


Grazie. Sì, ero solo un esempio. Al momento non c'era in mente un obiettivo specifico, voglio solo sapere come citare o sfuggire agli elementi dell'elenco da qualsiasi comando che potrebbe avere risultati individuali con spazi bianchi al loro interno.
Felix,

Una cosa che trovo confusa è perché l'espressione outer () nei tuoi file = ("$ {(@ f) $ (ls)}") è necessaria con @f? E solo giocare (f) sembra funzionare bene fino a quando () appare all'esterno.
Koobz,

@Koobz 1. Gli esterni (…)sono necessari in modo che filessia un array e non una stringa (che conterrebbe la concatenazione delle linee dal comando, annullando la divisione effettuata da (f)). 2. Con foo=$'one\n\nthree', contrast print -rl $ {(f) foo} `e print "${(@f)foo}". Le virgolette doppie sono necessarie per mantenere le righe vuote, che non otterrai lsma che possono accadere con altri comandi.
Gilles 'SO- smetti di essere malvagio' il

Molto apprezzato. C'è qualche rima o ragione per questa follia? Anche lì, ciò che confonde è il motivo per cui esterno () non divide nuovamente la stringa su singole parole se il valore intermedio è la mia stringa concatenata. Sembra ad esempio l'interpolazione di stringhe in ruby ​​o php.
Koobz,

@Koobz Il motivo del trattamento speciale delle parole vuote è la compatibilità storica con le versioni precedenti dimenticate da tempo di zsh. La ragione per non dividere automaticamente è che si tratta di un comportamento sorprendente e spesso non desiderabile. La divisione automatica è un comportamento della shell Bourne che zsh non emula a meno che non lo si dica.
Gilles 'SO- smetti di essere malvagio' il

2

In zsh puoi usare l'espansione della shell che non esegue la suddivisione delle parole per impostazione predefinita. Provare

for f in /path/to/files/*; do
    print ${f}
done
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.