> И IFS трогать ненужно и, по идее, там даже переносы строк
> не помеха.Да. Кавычки расставлены так, что при разворачивании всё оказывается целыми строками, независимо от наличия IFS или других специальных символов внутри значений. Различие между @ и * при развёртке массива.
Не трогая IFS можно вот так (Zenity заменена на find, для примера):
while read filename ; do
echo "I found name: '${filename}'"
done <<< "$( find /tmp -maxdepth 1 )"
В зависимости от реализации сам(и) IFS можно тронуть, если явно удобно. Если каждая строка это реально отдельный элемент массива (что не всегда), то можно вот так, с бэкапом IFS, если нужен:
Синтаксис описан здесь: https://wiki.bash-hackers.org/syntax/arrays
#!/bin/bashmkdir "/tmp/asd fgh" "/tmp/qwe rty"
IFS_back="${IFS}"
IFS=$'\n'
declare -a strings_array=($( ls -1 /tmp ))
for single_string in "${strings_array[@]}" ; do
if [[ "${single_string}" =~ ^"asd".*|.*" rty"$ ]] ; then # Прячу прочее содержимое своего /tmp, показываю только нужные имена.
echo $single_string
fi
done
IFS="${IFS_back}"
В зависимости от идеи бывает нужно сохранить для обработки позже. Причём IFS не трогается. Но больше вычислений - медленнее. Можно так:
declare -a str_array=()
while read filename ; do
str_array+=("${filename}")
done <<< "$( find /tmp -maxdepth 1 )"
echo "${str_array[0]}"
echo "${str_array[1]}"
echo "Total found: ${#str_array[@]}"
Либо ещё сильнее:
declare -A str_map=()
while read path ; do
str_map[$path]=$( basename "${path}" )
done <<< "$( find /tmp -maxdepth 1 )"for dir_name in "${!str_map[@]}" ; do
echo "Have file '${str_map[$dir_name]}' in '$(dirname "${dir_name}")'"
done
echo "Total found: ${#str_map[@]}"
Иногда по логике полезно применять логгирование и свал скрипта на первом возврате ошибки (рекомендации от Debian), объявления переменных readonly. Это позволяет гораздо меньше морочиться обработкой ошибок и быстрее их находить.
#!/bin/bash
PS4="+:$( basname \"\${0}\" ):\${LINENO}: "
set -xeu -o pipefail
declare -r some_name="asdfgh"
Применяется всё это примерно вот так:
#!/bin/bashPS4="+:$( basename \"\${0}\" ):\${LINENO}: "
set -xeu -o pipefail
function do_did_done {
local -A str_map
while read path ; do
str_map[$path]=$( basename "${path}" )
done <<< "$( find /tmp -maxdepth 1 )"
total_found="${#str_map[@]}"
}
total_found=0
do_did_done
set +e # Выключил свал.
false # Сгенерировал код возврата ошибка, а оно не падает.
echo "ИНФОРМАЦИЯ:${0}:${LINENO}: Total found ${total_found}" # Не залоггировало саму команду т.к. set +x
set -e # Включил свал обратно. Осторожно, при определённых условиях внутрь функции не наследуется.
set -x # Чтобы показало, на чём оно упадёт
declare -r dir_name="никогда-не-было-такой-директории"
test -d "${dir_name}" # А вот тут упало, с очень показательной диагностикой, т.к. set -e !!!
echo "Сюда уже не дойдёт."
По причине '<<<' - это Bash код.
По причине "declare -A" - это версия Bash 4+
До встречи в продакшн!! :)
P.S. Отвечая на старинный вопрос: зачем Вы используете эти башизмы '<<<'? Т.к. при таком приёме переменная, объявленная внутри цикла, сохранится по окончании цикла. Спасибо Opennet, здесь ведь научился.