Я пытался использовать bash для чтения файла символ за символом.
После долгих проб и ошибок я обнаружил, что это работает:
exec 4<file.txt
declare -i n
while read -r ch <&4;
n=0
while [ ! $n -eq ${#ch} ]
do echo -n "${ch:$n:1}"
(( n++ ))
done
echo ""
done
Т.е. я могу читать это построчно, а затем перебирать каждую строчку символ за символом.
Перед этим я попытался:
exec 4<file.txt && while read -r -n1 ch <&4; do; echo -n "$ch"; done
но он пропустил бы все пробелы в файле .
Не могли бы вы объяснить, почему? Есть ли способ заставить работать вторую стратегию (то есть чтение char за char с чтением bash)?
IFS
ничего не нужно, чтобы пробелы выживали при разделении слов.Ответы:
Вам нужно удалить пробельные символы из
$IFS
параметра,read
чтобы прекратить пропускать начальные и конечные-n1
символы (с помощью символа пробела, если он есть, и начальный, и конечный символы, поэтому пропускаются):Но даже тогда bash's
read
пропустит символы новой строки, с которыми вы можете обойти:Хотя вы можете использовать
IFS= read -d '' -rn1
вместо этого или даже лучшеIFS= read -N1
(добавлено в 4.1, скопировано изksh93
(добавлено вo
)) команду, которая читает один символ.Обратите внимание, что bash не
read
может справиться с NUL-символами. И у ksh93 есть те же проблемы, что и у bash.С зш:
(Zsh может справиться с NUL-символами).
Обратите внимание, что они
read -k/n/N
читают количество символов , а не байтов . Поэтому для многобайтовых символов им, возможно, придется читать несколько байтов, пока не будет прочитан полный символ. Если входные данные содержат недопустимые символы, вы можете получить переменную, которая содержит последовательность байтов, которая не образует допустимых символов и которую оболочка может в итоге считать за несколько символов . Например, в локали UTF-8:Это
\375
введет 6-байтовый символ UTF-8. Тем не менее, шестой (A
) выше недействителен для символа UTF-8. Вы по-прежнему получаете\375\200\200\200\200A
in$a
, которыйbash
считается как 6 символов, хотя первые 5 из них на самом деле не являются символами, только 5 байтов не являются частью какого-либо символа.источник
read -rN1
вместо этого решает проблему новой строки и, таким образом, устраняет необходимость предоставлять новую строку по умолчанию при печати$a
.read -n1
(char by char) занимает 4 минуты 51 секунду и нагревает ноутбук до 90 градусов. Использованиеread -r
(строка за строкой) занимает 1,3 секунды, а ноутбук работает на 54 градусах с двумя вентиляторами без звука.Это простой пример использования
cut
, аfor
цикл &wc
:Поцелуй не так ли?
источник
bash
решениеfile="$(</etc/passwd)"; bytes="${#file}"; for ((i=0;i<bytes;i++)); do echo "${file:i:1}"; done
?bash
«он слишком большой и слишком медленный». в соответствии с разделом ошибок на странице справки. Но даже в этом случае все еще быстрее нарезать строку в памяти, чем читать файл снова и снова для каждого символа. По крайней мере, на моей машине: pastebin.com/zH5trQQs