Я использую sh (не bash/csh) на FreeBSD 11 и не понимаю этого:
В консоли
Команда:zpool status -v
Результат:
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.
Разбиение на строки и построчная печать в скрипте:
#!/bin/sh
zp="$(zpool status -v)"
for line in $zp; do
echo "$line%"
done
Результат:
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%
Согласно всему, что я смог найти, синтаксис, который я использую, верен для sh и должен считывать по строке, а не по слову.
Что я упускаю?
решение1
Я озадачен тем, что вы нашли. Синтаксис, который вы использовали, верен для sh и разделяет по пробелам, а не только по новым строкам. Это широко документировано. Думать, что он разделяет по переносам строк, не является популярным заблуждением. (Не понимать, что он разделяет, является популярным заблуждением.)
Точнее, оставление переменной расширения без кавычек, как в $zp
, иногда называют оператором «split+glob». Вот что он делает:
- Возьмем значение переменной. Это строка.
- Разделить это значение на каждом символе-разделителе полей. Символ-разделитель полей — это тот, который находится в значении переменной
IFS
; по умолчанию эта переменная содержитпробел, табуляция и новая строка. (Это значение по умолчанию также используется, если переменная не задана.) Результатом является список строк. - Рассматривайте каждый элемент списка как шаблон wildcard (glob). Если он соответствует одному или нескольким именам файлов, этот элемент заменяется списком соответствующих имен файлов. В противном случае элемент остается один.
Например, если каталог содержит файлы с именами foo
, bar
и baz
, то следующий скрипт выведет три строки: a*
, bar
и baz
.
zq='a* b*'
for word in $zq; do echo "$word"; done
Если вы хотите разбить строку на новой строке, то вы можете сделать это, установив IFS
новую строку и отключив расширение подстановочных знаков.
#!/bin/sh
set -f
IFS='
'
zq=…
for line in $zq; do
…
done
Это применимо ко всем вариантам sh и csh.
Смотрите такжеПочему мой скрипт оболочки тормозит пробелы и другие специальные символы?
решение2
Чтобы прочитать строки, используйте встроенную в вашу оболочку функциючитатьфункция,
$помогите прочитать | голова -2
читать: читать [-ers] [-u fd] [-t тайм-аут] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...]
Одна строка считывается из стандартного ввода или из файлового дескриптора FD, если указана опция -u
Поместите это в while
цикл и, вуаля, у вас есть строки:
$ 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