Это на несколько порядков быстрее, чем применять wc -c к каждой строке!
Aerijman
@aerijman для этого типа проблем количество созданных процессов обычно больше всего влияет на производительность.
MarcH
Если строка в файле содержит смайлики, это не даст ожидаемой длины.
user5507535 08
@ user5507535, это зависит от того, какую «длину» вы на самом деле ожидаете. Есть много возможных определений Unicode (mawk использует байты, gawk не проверял).
Ян Худек
16
while IFS= read -r line; doecho${#line}; done < abc.txt
Это POSIX, поэтому он должен работать везде.
Изменить: добавлен -r, предложенный Уильямом.
Изменить: остерегайтесь обработки Unicode. Bash и zsh с правильно установленной локалью покажут количество кодовых точек, но тире покажет байты, поэтому вам нужно проверить, что делает ваша оболочка. Кроме того, в Юникоде есть много других возможных определений длины, так что это зависит от того, что вы действительно хотите.
Изменить: префикс с, IFS=чтобы избежать потери начальных и конечных пробелов.
+1, но ... это не удастся, если вход содержит '\'. Используйте read -r
Уильям Перселл 09
Если строка в файле содержит смайлики, это не даст ожидаемой длины.
user5507535 08
@ user5507535, на самом деле, это зависит от того, какую «длину» вы ожидаете. Есть много возможных определений Unicode (но в этом случае разные оболочки будут делать разные вещи).
Ян Худек
Всегда устанавливайте IFS=на readкоманду , когда требуется , чтобы читать в произвольных данных. Итак IFS= read -r. readиспользует IFSразделение слов для выполнения, и хотя все разделенные слова затем вставляются обратно вместе в одну доступную переменную ( line), нет гарантии, что они будут вставлены обратно вместе со всеми исходными символами-разделителями, которые у них были, или только с одним потенциально другим ед. Например, при использовании IFS по умолчанию строка foo barможет стать без foo bar7 пробелов. (Например, как Stack Overflow потерял соседние пробелы в этой строке примера в этом комментарии).
mtraceur
@mtraceur, в документации прямо говорится, что «оставшиеся слова и их промежуточные разделители присваиваются фамилии», поэтому они вставляются обратно вместе с исходным разделителем. Однако при этом не учитываются ведущие и замыкающие разделители, которые действительно потеряны. Итак, вы правы, IFSнужно настроить, но проблема, когда это не так, более тонкая.
Ян Худек
4
Я пробовал другие ответы, перечисленные выше, но они очень далеки от достойных решений при работе с большими файлами, особенно когда размер одной строки занимает более ~ 1/4 доступной оперативной памяти.
И bash, и awk проглатывают всю строку, хотя для этой проблемы это не нужно. Bash выдаст ошибку, если строка станет слишком длинной, даже если у вас достаточно памяти.
Я реализовал чрезвычайно простой, довольно неоптимизированный скрипт python, который при тестировании с большими файлами (~ 4 ГБ на строку) не хлюпает, и это намного лучшее решение, чем приведенные.
Если это критический по времени код для производства, вы можете переписать идеи на C или выполнить лучшую оптимизацию в вызове чтения (вместо чтения только одного байта за раз), после проверки того, что это действительно узкое место.
Код предполагает, что новая строка является символом перевода строки, что является хорошим предположением для Unix, но YMMV в Mac OS / Windows. Убедитесь, что файл заканчивается переводом строки, чтобы не пропустить счетчик символов последней строки.
from sys import stdin, exit
counter = 0
while True:
byte = stdin.buffer.read(1)
counter += 1
if not byte:
exit()
if byte == b'\x0a':
print(counter-1)
counter = 0
Этот "echo%" не обрабатывает небезопасные символы, требующие цитирования из оболочки. Кроме того, «xargs» будет разбивать ваш файл на пробелы и символы новой строки, а не только на новые строки, как того требовал исходный плакат.
Вы имели в виду echo -e | wc -m, не так ли? Бесполезное использование команд; оболочка может подсчитывать символы в переменной. Плюс echo -eполностью несовместим и работает в половине оболочек, в то время как запуск с одной escape-последовательностью работает в других и ничего в остальных.
while IFS= read -r line; do echo ${#line}; done < abc.txt
Это POSIX, поэтому он должен работать везде.
Изменить: добавлен -r, предложенный Уильямом.
Изменить: остерегайтесь обработки Unicode. Bash и zsh с правильно установленной локалью покажут количество кодовых точек, но тире покажет байты, поэтому вам нужно проверить, что делает ваша оболочка. Кроме того, в Юникоде есть много других возможных определений длины, так что это зависит от того, что вы действительно хотите.
Изменить: префикс с,
IFS=
чтобы избежать потери начальных и конечных пробелов.источник
IFS=
наread
команду , когда требуется , чтобы читать в произвольных данных. ИтакIFS= read -r
.read
используетIFS
разделение слов для выполнения, и хотя все разделенные слова затем вставляются обратно вместе в одну доступную переменную (line
), нет гарантии, что они будут вставлены обратно вместе со всеми исходными символами-разделителями, которые у них были, или только с одним потенциально другим ед. Например, при использовании IFS по умолчанию строкаfoo bar
может стать безfoo bar
7 пробелов. (Например, как Stack Overflow потерял соседние пробелы в этой строке примера в этом комментарии).IFS
нужно настроить, но проблема, когда это не так, более тонкая.Я пробовал другие ответы, перечисленные выше, но они очень далеки от достойных решений при работе с большими файлами, особенно когда размер одной строки занимает более ~ 1/4 доступной оперативной памяти.
И bash, и awk проглатывают всю строку, хотя для этой проблемы это не нужно. Bash выдаст ошибку, если строка станет слишком длинной, даже если у вас достаточно памяти.
Я реализовал чрезвычайно простой, довольно неоптимизированный скрипт python, который при тестировании с большими файлами (~ 4 ГБ на строку) не хлюпает, и это намного лучшее решение, чем приведенные.
Если это критический по времени код для производства, вы можете переписать идеи на C или выполнить лучшую оптимизацию в вызове чтения (вместо чтения только одного байта за раз), после проверки того, что это действительно узкое место.
Код предполагает, что новая строка является символом перевода строки, что является хорошим предположением для Unix, но YMMV в Mac OS / Windows. Убедитесь, что файл заканчивается переводом строки, чтобы не пропустить счетчик символов последней строки.
from sys import stdin, exit counter = 0 while True: byte = stdin.buffer.read(1) counter += 1 if not byte: exit() if byte == b'\x0a': print(counter-1) counter = 0
источник
Вот пример использования
xargs
:$ xargs -d '\n' -I% sh -c 'echo % | wc -c' < file
источник
Попробуй это:
while read line do echo -e |wc -m done <abc.txt
источник
echo -e | wc -m
, не так ли? Бесполезное использование команд; оболочка может подсчитывать символы в переменной. Плюсecho -e
полностью несовместим и работает в половине оболочек, в то время как запуск с одной escape-последовательностью работает в других и ничего в остальных.