Я удивлен, что никто не упомянул очевидное bashрешение, использующее только whileи read.
while read -n1 character; do
echo "$character"
done < <(echo -n "$words")
Обратите внимание на использование, echo -nчтобы избежать лишней новой строки в конце. printf- еще один хороший вариант, который может больше подойти для ваших нужд. Если вы хотите игнорировать пробелы, замените их "$words"на "${words// /}".
Другой вариант есть fold. Обратите внимание, однако, что он никогда не должен попадать в цикл for. Вместо этого используйте цикл while следующим образом:
while read char; do
echo "$char"
done < <(fold -w1 <<<"$words")
Основным преимуществом использования внешней foldкоманды ( пакета coreutils ) будет краткость. Вы можете передать его вывод другой команде, такой как xargs(часть пакета findutils ), следующим образом:
fold -w1 <<<"$words" | xargs -I% -- echo %
Вы захотите заменить echoкоманду, используемую в приведенном выше примере, на команду, которую вы хотите запускать для каждого персонажа. Обратите внимание, что xargsпо умолчанию отбрасываются пробелы. Вы можете использовать, -d '\n'чтобы отключить это поведение.
Интернационализация
Я только что протестировал foldнекоторые азиатские символы и понял, что у них нет поддержки Unicode. Так что, хотя он подходит для нужд ASCII, он не сработает для всех. В этом случае есть несколько альтернатив.
Я бы, наверное, заменил fold -w1массивом awk:
awk 'BEGIN{FS=""} {for (i=1;i<=NF;i++) print $i}'
Или grepкоманда, упомянутая в другом ответе:
grep -o .
Спектакль
К вашему сведению, я проверил 3 вышеупомянутых варианта. Первые два были быстрыми, почти завязывающими, а петля сгиба была немного быстрее, чем петля while. Неудивительно, что он xargsбыл самым медленным ... в 75 раз медленнее.
Вот (сокращенный) тестовый код:
words=$(python -c 'from string import ascii_letters as l; print(l * 100)')
testrunner(){
for test in test_while_loop test_fold_loop test_fold_xargs test_awk_loop test_grep_loop; do
echo "$test"
(time for (( i=1; i<$((${1:-100} + 1)); i++ )); do "$test"; done >/dev/null) 2>&1 | sed '/^$/d'
echo
done
}
testrunner 100
Вот результаты:
test_while_loop
real 0m5.821s
user 0m5.322s
sys 0m0.526s
test_fold_loop
real 0m6.051s
user 0m5.260s
sys 0m0.822s
test_fold_xargs
real 7m13.444s
user 0m24.531s
sys 6m44.704s
test_awk_loop
real 0m6.507s
user 0m5.858s
sys 0m0.788s
test_grep_loop
real 0m6.179s
user 0m5.409s
sys 0m0.921s