Qual é o efeito de “$ {(@ f)…}” em Zsh?

4

Eu encontrei um script Zsh e quis saber seu significado. Nos scripts abaixo, há ${$(@f)$(egrep "$2","$file")} expressão. Pelo que eu pesquisei, @ é usado para representar todos os parâmetros posicionais, mas a letra do postfix f não é mencionada em nenhum lugar no script acima e eu não encontrei nenhum material on-line dizendo seu significado especial.

#!/usr/bin/env zsh

tmp_file="/tmp/_unsorted_find_n_grep"
echo "--- find <$2> in <$1>" > $tmp_file

find . -follow -iname "$1" | while read file
do
    timestamp=$(ls -l --time-style=+"%Y-%m-%d %H:%M:%S" "$file" | gawk '{print $6, $7}')
    linestack=${(@f)$(egrep "$2" "$file")}
    for line in $linestack 
do
    echo "$timestamp $file: $line" >> $tmp_file
done
done

cat $tmp_file | sort
rm $tmp_file
    
por NathaneilCapital 27.01.2014 / 17:31

2 respostas

2

O caractere dentro dos parênteses é sinalizadores de expansão de parâmetro . Eles podem ser usados em torno de uma substituição de variável ou uma substituição de comando, por exemplo,

${(@f)SOME_VARIABLE}
${(@f)${(xyz)SOME_VARIABLE}}
${(@f)$(some-command)}

O sinalizador f divide o resultado da expansão em novas linhas. O sinalizador @ garante que a matriz resultante seja expandida como várias palavras; Curiosamente, só tem efeito dentro de aspas duplas, onde atua como uma generalização de "$@" .

Normalmente, esses sinalizadores são usados assim:

lines=("${(@f)$(egrep "$2" "$file")}")

Dessa forma, lines se torna uma matriz na qual cada elemento é uma linha de saída de egrep .

Aqui, a expansão não está em um contexto que permite várias palavras, portanto, o sinalizador @ não tem efeito. O efeito do sinalizador f é um pouco não intuitivo: ele força um contexto de matriz, portanto as palavras separadas por IFS na saída egrep são armazenadas em uma matriz temporária que é então unida ao primeiro caractere de IFS . / p>

linestack=${(@f)$(egrep "$2" "$file")}

Contraste:

$ zsh -c 'a=${(f)$(echo hello world; echo wibble)}; print -lr $#a $a'
18
hello world wibble
$ zsh -c 'IFS=:$IFS; a=${(f)$(echo hello world; echo wibble)}; print -lr $#a $a'
18
hello:world:wibble
$ zsh -c 'IFS=:; a=${(f)$(echo hello world; echo wibble)}; print -lr $#a $a'
18
hello world
wibble

$ zsh -c 'a=(${(f)$(echo hello world; echo wibble)}); print -lr $#a $a' 
1
hello world wibble
$ zsh -c 'a=("${(@f)$(echo hello world; echo wibble)}"); print -lr $#a $a'
2
hello world
wibble
    
por 27.01.2014 / 22:38
0

De acordo com esta documentação do zsh

@    In double quotes, array elements are put into separate words. E.g., ‘"${(@)foo}"’
     is equivalent to ‘"${foo[@]}"’ and ‘"${(@)foo[1,2]}"’ is the same as ‘"$foo[1]"
     "$foo[2]"’. This is distinct from field splitting by the f, s or z flags, which still
     applies within each array element.
    
por 27.01.2014 / 19:36