Dividir o array zsh do subshell por linebreak

3

Gostaria de instanciar uma matriz zsh de um subshell

myarray=($(somecommand)

e eu verifico se recebi o que queria com

for element in $myarray ; do echo "===" ; echo $element ; echo "---" ; done

Por padrão, vejo que os espaços em branco (espaços e quebras de linha) são usados para separar elementos.

Também descobri que posso usar ${(s:-:)"$(somecommand)"} para separar por - . Nesse caso, espaços e quebras de linha não quebram elementos (ou seja, elementos de matriz podem conter quebras de linha).

Até agora não consegui dividir apenas as quebras de linha. Ou seja se somecommand retornar

Alice
Bob
Arthur C Clarke
Neo
Thomas Anderson

Eu quero que meu loop for acima seja impresso:

===
Alice
---
===
Bob
---
===
Arthur C Clarke
---
===
Neo
---
===
Thomas Anderson
---

Como faço para conseguir isso? (E, possivelmente, ponteiros onde procurar isso no manual.)

    
por pseyfert 06.08.2018 / 11:19

1 resposta

5

O operador de divisão nativa (ao lado da divisão de palavras parecida com o Bourne $IFS , que é feita em substituições de comando sem aspas) está com o sinalizador de expansão do parâmetro s :

array=(${(ps:\n:)"$(cmd)")

dividiria a saída de cmd na nova linha, descartando os elementos vazios (as linhas vazias).

p é ativar as expansões \x . Como ps:\n: é comum, ele tem um alias mais curto: f (para dividir em linha f eeds):

array=(${(f)"$(cmd)")

Para preservar as linhas vazias, você faria:

array=("${(f@)$(cmd)")

Agora, cuidado, como na maioria dos outros shells, a substituição de comandos retira todos os caracteres de nova linha, de forma que todas as linhas vazias sejam arrastadas. Para preservar, você pode fazer:

array=("${(f@)$(cmd; echo .)")
array[-1]=()  # remove that last line added by echo .

Com $IFS divisão de palavras:

IFS=$'\n'
array=($(cmd)) # removes empty lines. Note that contrary to other
               # Bourne-like shells, zsh doesn't to globbing there
               # so you don't need the "set -o noglob"

IFS=$'\n\n' # like in ksh93, doubling an IFS-whitespace character
            # removes its special treatment as a whitespace character
array=($(cmd)) # preserves empty lines except the trailing ones

IFS=$'\n\n'
array=($(cmd; echo .)); array[-1]=() # preserves all empty lines.

Para evitar a modificação de $IFS globalmente, você pode fazer o acima em uma função anônima:

(){
  local IFS=$'\n\n'
  array=($(cmd; echo .)); array[-1]=()
}

Tenha também em atenção que a expansão $array ignora os elementos vazios. Então, se você quisesse fazer um loop sobre todos os elementos, incluindo os elementos vazios, seria necessário:

for i ("$array[@]") ...

ou

for i ("${(@)array}") ...

não

for i ($array) ...
for i in $array
    
por 06.08.2018 / 11:43