Вопрос или проблема
Я пытаюсь пройтись по переменной, которая содержит переносы строк, совместимым с POSIX способом.
Следующий вариант работает:
echo "$REQUIRE_PURPOSE" | while IFS= read -r line ; do
echo "$line"
done
но конвейер запускает другую оболочку.
Я попробовал:
OLDIFS="$IFS"
IFS='
'
for line in "$REQUIRE_PURPOSE"; do
echo "$line"
done
IFS="$OLDIFS"
Но это просто выводит содержимое "$REQUIRE_PURPOSE"
Я также пробовал:
while IFS= read -r line ; do
echo "$line"
done <<< "$REQUIRE_PURPOSE"
но и здесь это не работает.
Пример:
echo "$REQUIRE_PURPOSE"
echo "---"
while IFS= read -r line ; do echo "$line"; done <<< "$REQUIRE_PURPOSE"
генерирует:
uuu
iii
Цифровая подпись
---
uuuniiinЦифровая подпись
или
00000000 75 75 75 0a 69 69 69 0a 44 69 67 69 74 61 6c 20 |uuu.iii.Дигит. |
00000010 53 69 67 6e 61 74 75 72 65 0a 2d 2d 2d 0a 31 20 |Подпись.---.1 |
00000020 75 75 75 6e 69 69 69 6e 44 69 67 69 74 61 6c 20 |uuuniiinЦифров. |
00000030 53 69 67 6e 61 74 75 72 65 0a 75 75 75 0a 69 69 |Подпись.uuu.ii|
00000040 69 0a 44 69 67 69 74 61 6c 20 53 69 67 6e 61 74 |i.Цифровая Подп.|
00000050 75 72 65 0a |ь.|
00000054
Есть идеи?
Опция для read
, которая вам нужна, – это -a
. Она разобьет ввод по IFS
на массив:
read -a lines <<<"$REQUIRE_PURPOSE"
for i in "${lines[@]}"
do
echo "$i"
done
Вы можете сделать это с помощью расширения параметров (S.2.6.2) и подстановки команд (S.2.6.3) внутри некотированного HereDoc (S2.7.4):
VAR="$(echo Line1; echo Line2; echo EOF; echo "HereDoc продолжается."; echo Line5)"
while read line; do
printf "Строка-%s-КОНЕЦ\n" "$line"
done << EOF
$VAR
EOF
while read line; do
printf "Строка-%s-КОНЕЦ\n" "$line"
done << EOF
$(
echo Line1
echo Line2
echo EOF
echo "HereDoc продолжается."
echo Line5
)
EOF
Ответ или решение
Эффективный подход к перебору переменной с разделителями строки в POSIX
При работе с переменными, содержащими новые строки, важно найти способ обходиться без лишних подсистем и обеспечивать правильную обработку данных. В этом ответе мы рассмотрим, как можно перебирать строки переменной, используя минималистичные и эффективные подходы с учетом стандартов POSIX.
Проблема
Исходная проблема заключается в том, что попытки использовать while IFS= read -r line; do ...; done <<< "$REQUIRE_PURPOSE"
приводят к некорректному выводу. Это связано с неправильным использованием новых строк и разделителей. Кроме того, использование конвейеров (|
) приводит к запуску новой подсистемы, что нежелательно в данном контексте.
Решения
-
Использование массива с опцией
-a
дляread
:
Один из эффективных способов обхода проблемы — это загрузка содержимого переменной в массив с помощью командыread
:read -a lines <<< "$REQUIRE_PURPOSE" for line in "${lines[@]}"; do echo "$line" done
В этом варианте содержимое переменной
$REQUIRE_PURPOSE
разбивается на строки на основе значенийIFS
, которые по умолчанию равны пробелам и символам новых строк. Это позволяет перебирать строки в массиве без подсистем. -
Применение параметрической подстановки и командной подстановки:
Вам также может подойти подход с использованием хердоков (here documents):VAR="$(echo Line1; echo Line2; echo EOF; echo "HereDoc продолжается."; echo Line5)" while read line; do printf "Line-%s-END\n" "$line" done << EOF $VAR EOF
Этот пример демонстрирует, как можно использовать переменную
VAR
в комбинации с хердоком. Он работает, посколькуVAR
может содержать любые строки, которые необходимо обработать. -
Использование цикла
while
и прямой подстановки:
Если вы хотите избежать проверки массива, вы можете использовать прямую подстановку в циклеwhile
:while read -r line; do echo "$line" done <<< "$REQUIRE_PURPOSE"
Однако, как уже упоминалось, это создаёт дочерний процесс, что может быть нежелательно.
Заключение
Перебор переменной с новыми строками в зависимости от ваших требований можно осуществить различными способами, каждый из которых имеет свои плюсы и минусы. Использование массива с read -a
является наиболее оптимальным методом, так как он соответствует стандартам POSIX и минимизирует накладные расходы. Если вам нужна гибкость и возможность обрабатывать сложные входные данные, подход с хердоками будет эффективен.
Для достижения наилучших результатов тестируйте каждое решение в контексте вашей конкретной среды и задач, чтобы выбрать наиболее подходящее.