Ответ 1
Оказывается, ваш ответ неверен. Да, ты можешь! вам нужно использовать переключатель -d
в read
:
-d
delimПервый символ delim используется для завершения строки ввода, а не для новой строки.
Если вы используете его с пустым аргументом, bash использует нулевой байт в качестве разделителя:
$ var=$'/path/to/filename.ext\n/path/to/filename2.ext\n/path/to/filename3.ext'
$ IFS=$'\n' read -r -d '' -a arr < <(printf '%s\0' "$var")
$ declare -p arr
declare -a arr='([0]="/path/to/filename.ext" [1]="/path/to/filename2.ext" [2]="/path/to/filename3.ext")'
Успех. Здесь мы используем замену процесса с помощью printf
, которая просто сбрасывает содержимое переменной с конечным нулевым байтом, так что read
счастлив и возвращает код возврата успеха. Вы можете использовать:
IFS=$'\n' read -r -d '' -a arr <<< "$var"
В этом случае содержание arr
является одинаковым; единственное отличие состоит в том, что код возврата read
равен 1
(сбой).
В качестве побочного примечания: существует разница между
$ IFS=$'\n'
$ read ...
и
$ IFS=$'\n' read ...
Первый устанавливает IFS
глобально (т.е. IFS
сохранит это значение для оставшейся части script - пока вы не измените его снова, конечно): вы, скорее всего, не захотите этого делать
Последний устанавливает только IFS
для команды read
. Вы, конечно, хотите использовать его таким образом!
Еще одно примечание: о вашем методе 1. Вам не хватает кавычек, вы не отключаете IFS
, и вы не используете флаг -r
для read
. Это плохо:
while read line; do
arr+=($line)
done <<< "$var"
Это хорошо:
while IFS= read -r line; do
arr+=( "$line" )
done <<< "$var"
Почему?
- не отбрасывая
IFS
, вы удалите удаленные пробелы и начало. - Без
-r
некоторые обратные косые черты будут пониматься как экранирование обратных косых черт (\'
, trailing\
,\
и, возможно, другие). - Без правильного цитирования
( "$line" )
вы получите расширение слова и расширение имени файла: вы не хотите, чтобы на вашем входе содержались пробелы или символы глобуса (например,*
,[
,?
, и т.д.).