Lendo a saída do comando na variável no shell, divide o texto em cada espaço em branco e não apenas na linha

0

Estou usando sh (não bash / csh) no FreeBSD 11, e não entendo isso:

No console

Comando: zpool status -v

Resultado:

  pool: My_pool
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.

Divisão por linhas e linha de impressão por vez em um script:

#!/bin/sh
zp="$(zpool status -v)"
for line in $zp; do
  echo "$line%"
done

Resultado:

pool:%
My_pool%
state:%
ONLINE%
status:%
One%
or%
more%
devices%
is%
currently%
being%
resilvered.%
The%
pool%
will%
continue%
to%
function,%
possibly%
in%
a%
degraded%
state.%
action:%
Wait%

De acordo com tudo que eu posso encontrar, a sintaxe que estou usando é correta para sh, e deve ler uma linha de cada vez, não uma palavra de cada vez.

O que estou perdendo?

    
por Stilez 28.11.2017 / 23:11

2 respostas

3

Estou confuso sobre o que você encontrou. A sintaxe que você usou está correta para sh e divide em espaços em branco, não apenas em novas linhas. Isso é amplamente documentado. Pensar que se divide em quebra de linha não é um equívoco popular. (Não entender que ele se separa é um equívoco popular.)

Mais precisamente, deixar uma expansão variável sem aspas, como em $zp , às vezes é apelidado de operador "split + glob". O que isso faz é:

  1. Pegue o valor da variável. Essa é uma string.
  2. Divida esse valor em cada caractere separador de campo. Um caractere separador de campo é aquele que está no valor da variável IFS ; Por padrão, essa variável contém um espaço , uma guia e uma nova linha . (Esse padrão também é usado se a variável não estiver definida.) O resultado é uma lista de seqüências de caracteres.
  3. Considere cada elemento da lista como um padrão curinga (glob). Se corresponder a um ou mais nomes de arquivo, esse elemento será substituído pela lista de nomes de arquivos correspondentes. Caso contrário, o elemento é deixado em paz.

Por exemplo, se o diretório contiver arquivos chamados foo , bar e baz , o script a seguir imprimirá três linhas: a* , bar e baz .

zq='a* b*'
for word in $zq; do echo "$word"; done

Se você quiser dividir uma string em novas linhas, você pode definir IFS para uma nova linha e desabilitar a expansão de caracteres curinga.

#!/bin/sh
set -f
IFS='
'
zq=…
for line in $zq; do
  …
done

Isso se aplica a todas as variantes sh e csh.

Veja também meu shell script engasga com espaço em branco ou outros caracteres especiais?

    
por 28.11.2017 / 23:24
0

Para ler linhas, use a função read do seu shell,

$ help read | head -2

read: read [-ers] [-u fd] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...]

One line is read from the standard input, or from file descriptor FD if the -u option is supplied

Coloque dentro de um loop while e, voila, você tem linhas:

$ wc -l -w ~/.profile 
  24      47 /Users/jklowden/.profile
$ for W in $(cat ~/.profile); do echo $W; done | wc -l 
  47
$ while read L; do echo $L; done < ~/.profile | wc -l 
  24
    
por 29.11.2017 / 02:31