У меня есть переменная, которая содержит многострочный вывод команды. Какой самый эффективный способ читать вывод построчно из переменной?
Например:
jobs="$(jobs)"
if [ "$jobs" ]; then
# read lines from $jobs
fi
Вы можете использовать цикл while с подстановкой процесса:
while read -r line
do
echo "$line"
done < <(jobs)
Оптимальный способ чтения многострочной переменной - установить пустую IFS
переменную и printf
переменную с завершающим символом новой строки:
# Printf '%s\n' "$var" is necessary because printf '%s' "$var" on a
# variable that doesn't end with a newline then the while loop will
# completely miss the last line of the variable.
while IFS= read -r line
do
echo "$line"
done < <(printf '%s\n' "$var")
Примечание. В соответствии с проверкой оболочки sc2031 использование подстановки процесса предпочтительнее, чем конвейер, чтобы избежать [тонкого] создания подоболочки.
Также, пожалуйста, поймите, что присвоение имени переменной jobs
может вызвать путаницу, так как это также имя обычной команды оболочки.
while IFS= read
.... Если вы хотите предотвратить \ интерпретацию, тогда используйтеread -r
echo
наprintf %s
так, чтобы ваш сценарий работал даже при нестандартном вводе./tmp
каталог был доступен для записи, поскольку он полагается на возможность создания временного рабочего файла. Если вы когда-нибудь окажетесь в системе с ограниченным доступом/tmp
, доступной только для чтения (и не подлежащей изменению вами), вы будете рады возможности использовать альтернативное решение, например, сprintf
конвейером.printf "%s\n" "$var" | while IFS= read -r line
Чтобы обработать вывод командной строки построчно ( объяснение ):
Если у вас уже есть данные в переменной:
printf %s "$foo"
почти идентиченecho "$foo"
, но печатает$foo
буквально, тогда какecho "$foo"
может интерпретироваться$foo
как опция команды echo, если она начинается с a-
, и может расширять последовательности обратной косой черты$foo
в некоторых оболочках.Обратите внимание, что в некоторых оболочках (ash, bash, pdksh, но не в ksh или zsh) правая часть конвейера выполняется в отдельном процессе, поэтому любая переменная, заданная в цикле, теряется. Например, следующий скрипт подсчета строк выводит 0 в этих оболочках:
Обходной путь - поместить оставшуюся часть скрипта (или, по крайней мере, ту часть, которая нуждается в значении
$n
цикла) в список команд:Если действия с непустыми строками достаточно хороши, а ввод невелик, вы можете использовать разбиение слов:
Объяснение: установка
IFS
на одну новую строку приводит к разделению слов только на новых строках (в отличие от любого символа пробела при настройке по умолчанию).set -f
отключает подстановку (т. е. расширение по шаблону), что в противном случае могло бы произойти в результате подстановки команды$(jobs)
или переменной substitutino$foo
.for
Петля действует на все части$(jobs)
, которые являются все непустые строки в выходных данных команды. Наконец-то восстановим сглаживание иIFS
настройки.источник
local IFS=something
. Это не повлияет на значение глобальной области видимости. IIRC,unset IFS
не возвращает вас к значениям по умолчанию (и, конечно, не работает, если это не было заранее задано по умолчанию).Проблема: если вы используете цикл while, он будет работать в подоболочке и все переменные будут потеряны. Решение: использовать для цикла
источник
while read
цикл в bash означает, что цикл while находится в подоболочке, поэтому переменные не являются глобальными.while read;do ;done <<< "$var"
делает тело цикла не подоболочкой (У недавнего bash есть возможность поместить телоcmd | while
цикла не в подоболочку, как всегда было в ksh.)В последних версиях bash используйте
mapfile
илиreadarray
для эффективного чтения вывода команд в массивыОтказ от ответственности: ужасный пример, но вы можете придумать лучшую команду для использования, чем вы сами
источник
readarray
функцию и вызовите функцию несколько раз.Рекомендации:
while
IFS
read
источник
-r
это тоже хорошая идея; Это предотвращает\` interpretation... (it is in your links, but its probably worth mentioning, just to round out your
IFS = `(что важно для предотвращения потери пробела)Вы можете использовать <<< для простого чтения из переменной, содержащей разделенные строкой данные:
источник