Estoy usando sh (no bash/csh) en FreeBSD 11 y no entiendo esto:
En consola
Dominio: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.
Dividir por líneas e imprimir línea a la vez en un guión:
#!/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%
Según todo lo que puedo encontrar, la sintaxis que estoy usando es correcta para sh y debería leer una línea a la vez, no una palabra a la vez.
¿Qué me estoy perdiendo?
Respuesta1
Estoy desconcertado por lo que encontró. La sintaxis que utilizó es correcta para sh y se divide en espacios en blanco, no solo en nuevas líneas. Esto está ampliamente documentado. Pensar que se divide en los saltos de línea no es un error popular. (No entender que sí se divide es un error popular).
Más precisamente, dejar una expansión variable sin comillas, como en $zp
, a veces recibe el apodo de operador “split+glob”. Lo que hace es:
- Toma el valor de la variable. Esa es una cuerda.
- Divida este valor en cada carácter separador de campo. Un carácter separador de campo es aquel que está en el valor de la variable
IFS
; De forma predeterminada, esta variable contiene unespacio, una pestaña y una nueva línea. (Este valor predeterminado también se usa si la variable no está configurada). El resultado es una lista de cadenas. - Considere cada elemento de la lista como un patrón comodín (glob). Si coincide con uno o más nombres de archivos, ese elemento se reemplaza por la lista de nombres de archivos coincidentes. De lo contrario, el elemento se deja solo.
Por ejemplo, si el directorio contiene archivos llamados y foo
, el siguiente script imprime tres líneas : y .bar
baz
a*
bar
baz
zq='a* b*'
for word in $zq; do echo "$word"; done
Si desea dividir una cadena en nuevas líneas, puede hacerlo estableciendo IFS
una nueva línea y deshabilitando la expansión de comodines.
#!/bin/sh
set -f
IFS='
'
zq=…
for line in $zq; do
…
done
Esto se aplica a todas las variantes de sh y csh.
Ver también¿Por qué mi script de shell se atasca con espacios en blanco u otros caracteres especiales?
Respuesta2
Para leer líneas, use la función integrada de su shellleerfunción,
$ayuda leer | cabeza -2
leer: leer [-ers] [-u fd] [-t tiempo de espera] [-p símbolo] [-a matriz] [-n nchars] [-d delim] [nombre...]
Se lee una línea de la entrada estándar o del descriptor de archivo FD si se proporciona la opción -u
Ponlo dentro de un while
bucle y listo, tienes líneas:
$ 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