Команда оболочки Linux для фильтрации текстового файла по длине строки

19

У меня 30-гигабайтный образ диска с разделенным на части разделом (думаю dd if=/dev/sda1 of=diskimage), из которого мне нужно восстановить некоторые текстовые файлы. Инструменты для вырезания данных, например, foremostработают только с файлами с четко определенными заголовками, то есть не с простыми текстовыми файлами, поэтому я остановился на своем хорошем друге strings.

strings diskimage > diskstrings.txt создал 3-гигабайтный текстовый файл, содержащий кучу строк, в основном бесполезных, смешанных с текстом, который я на самом деле хочу.

Большая часть хутора имеет тенденцию быть действительно длинными, непрерывными рядами тарабарщины. Вещи, которые меня интересуют, гарантированно будут меньше 16 КБ, поэтому я собираюсь отфильтровать файл по длине строки. Вот скрипт Python, который я использую для этого:

infile  = open ("infile.txt" ,"r");
outfile = open ("outfile.txt","w");
for line in infile:
    if len(line) < 16384:
        outfile.write(line)
infile.close()
outfile.close()

Это работает, но для дальнейшего использования: существуют ли магические заклинания в одну строку (думаю awk, sed), которые бы фильтровали файл по длине строки?

Ли Аунг Йип
источник

Ответы:

28
awk '{ if (length($0) < 16384) print }' yourfile >your_output_file.txt

будет печатать строки короче 16 килобайт, как в вашем собственном примере.

Или, если вам нравится Perl:

perl -nle 'if (length($_) < 16384) { print }' yourfile >your_output_file.txt
Янне Пиккарайнен
источник
Ну, это было невероятно просто. Спасибо. :)
Ли-Аунг Ип
Добавлена ​​также версия на Perl :-)
Janne Pikkarainen
А сценарий awk может быть записан как awk 'length($0) < 16384' file > output, так как действие по умолчанию - печать строки.
Гленн Джекман
8

Это похоже на ответ Ансгара, но немного быстрее в моих тестах:

awk 'length($0) < 16384' infile >outfile

Это та же скорость, что и другие ответы awk. Он опирается на неявное printистинное выражение, но не требует времени, чтобы разделить линию, как это делает Ансгар.

Обратите внимание, что AWK дает вам ifбесплатно. Команда выше эквивалентна:

awk 'length($0) < 16384 {print}' infile >outfile

Нет явного if(или окружающего его набора фигурных скобок), как в некоторых других ответах.

Вот способ сделать это в sed:

sed '/.\{16384\}/d' infile >outfile

или:

sed -r '/.{16384}/d' infile >outfile

которые удаляют любую строку, содержащую 16384 (или более) символов.

Для полноты, вот как бы вы использовали, sedчтобы сохранить строки длиннее порога:

sed '/^.\{0,16383\}$/d' infile >outfile
Приостановлено до дальнейшего уведомления.
источник
2

Вы можете awkтакие как:

$ awk '{ if (length($0) < 16384) { print } }' /path/to/text/file

Это напечатает строки длиннее 16K символов (16 * 1024).

Вы также можете использовать grep:

$ grep ".\{,16384\}" /path/to/text/file

Это напечатает строки не более 16K символов.

Халед
источник
Не уверен, что grepэто хорошая идея - это, конечно, простое регулярное выражение, но дороже в вычислительном отношении, чем awk. «Человек с проблемой говорит:« Я буду использовать регулярные выражения! »Теперь у него две проблемы». ;)
Ли-Аунг Ип
Это просто еще один способ сделать это. Первый вариант, который я опубликовал, использовал awk.
Халед
1
+1 за регулярное выражение, потому что это лучше в гольф, и это не заставляет меня читать страницы справочника awk =)
Сиро Сантилли 新疆 改造 中心 法轮功 六四 事件
2

Не очень отличается от уже полученных ответов, но все же короче:

awk -F '' 'NF < 16384' infile >outfile
Ансгар Эстерманн
источник