В качестве альтернативы итерации по 0 .. ${#string}-1
с циклом for / while есть два других способа, с которыми я могу думать: только bash : используя =~
и используя printf
]. (Существует третья возможность использования выражения eval
и {..}
последовательности, но это не имеет ясности.)
С правильной средой и поддержкой NLS в bash они будут работать с не-ASCII, как можно надеяться, удаляя потенциальные источники сбоев со старыми системными инструментами, такими как sed
, если это вызывает беспокойство.
Используя =~
и регулярные выражения, преобразуя строку в массив в одном выражении:
string="wonkabars"
[[ "$string" =~ ${string//?/(.)} ]] # splits into array
printf "%s\n" "${BASH_REMATCH[@]:1}" # loop free: reuse fmtstr
declare -a arr=( "${BASH_REMATCH[@]:1}" ) # copy array for later
Способ это работает, чтобы выполнить расширение string
, которое заменяет каждый отдельный символ для (.)
, а затем сопоставляет это сгенерированное регулярное выражение с группировкой для захвата каждого отдельного символа в BASH_REMATCH[]
. Индекс 0 установлен на всю строку, так как этот специальный массив доступен только для чтения, вы не можете его удалить, обратите внимание на :1
, когда массив расширен, чтобы пропустить индекс 0, если это необходимо. Некоторые быстрые тесты для нетривиальных строк (> 64 символа) показывают, что этот метод существенно быстрее, чем один, используя операции bash и операции с массивом.
Вышеупомянутое будет работать со строками, содержащими строки новой строки , =~
поддерживает POSIX ERE, где .
по умолчанию совпадает с чем-либо, кроме NUL , то есть регулярное выражение скомпилировано без REG_NEWLINE
. (Поведение POSIX-обработки текста утилит по умолчанию по-разному отличается и обычно является.)
Вторая опция, используя printf
:
string="wonkabars"
ii=0
while printf "%s%n" "${string:ii++:1}" xx; do
((xx)) && printf "\n" || break
done
Этот цикл увеличивает индекс ii
для печати одного символа за раз и разрывается, когда символов нет. Это было бы еще проще, если bash printf
вернул количество символов, напечатанных (как на C), а не статус ошибки, вместо этого количество напечатанных символов будет записано в xx
с помощью %n
. (Это работает как минимум до bash-2.05b.)
С bash-3.1 и printf -v var
у вас немного больше гибкости и вы можете избежать падения с конца строки, если вы будете делать что-то, кроме печати символов, например для создания массива:
declare -a arr
ii=0
while printf -v cc "%s%n" "${string:(ii++):1}" xx; do
((xx)) && arr+=("$cc") || break
done