13

У меня есть большое количество файлов, некоторые из которых очень длинные. Я хотел бы обрезать их до определенного размера, если они больше, удалив конец файла. Но я хочу только удалить целые строки. Как я могу это сделать? Это похоже на то, что будет обрабатываться набором инструментов Linux, но я не знаю правильной команды.

Например, скажем, у меня есть файл размером 120000 байт с 300-байтовыми строками, и я пытаюсь обрезать его до 10000 байт. Первые 33 строки должны остаться (9900 байт), а остальные должны быть обрезаны. Я не хочу точно вырезать 10 000 байт, так как это оставит частичную строку.

Конечно, файлы имеют разную длину, а строки имеют разную длину.

В идеале результирующие файлы должны быть немного короче, чем чуть длиннее (если точка останова находится на длинной строке), но это не так уж важно, это может быть немного длиннее, если это будет проще. Я хотел бы, чтобы изменения были внесены непосредственно в файлы (ну, возможно, новый файл скопирован в другом месте, оригинал удален, а новый файл перемещен, но это то же самое из пользовательского POV). Решение, которое перенаправляет данные в кучу мест, а затем обратно предлагает возможность повреждения файла, и я хотел бы избежать этого ...

5 ответов5

14

Подход sed хорош, но перебирать все строки нельзя. Если вы знаете, сколько строк вы хотите сохранить (для примера, я использую здесь 99), вы можете сделать это следующим образом:

sed -i '100,$ d' myfile.txt

Пояснение: sed - это процессор регулярных выражений. С заданной опцией -i он обрабатывает файл напрямую ("inline") - вместо того, чтобы просто читать его и записывать результаты в стандартный вывод. 100,$ означает просто "от строки 100 до конца файла" - и сопровождается командой d , которую вы, вероятно, догадались правильно, чтобы заменить "удалить". Короче говоря, команда означает: «Удалить все строки из строки 100 до конца файла из myfile.txt». 100 - это первая строка, которую нужно удалить, так как вы хотите сохранить 99 строк.

Редактировать: Если, с другой стороны, есть файлы журналов, где вы хотите сохранить, например, последние 100 строк:

[ $(wc -l myfile.txt) -gt 100 ] && sed -i "1,$(($(wc -l myfile.txt|awk '{print $1}') - 100)) d" myfile.txt

Что здесь происходит:

  • [ $(wc -l myfile.txt) -gt 100 ]: делайте следующее, только если файл содержит более 100 строк
  • $((100 - $(wc -l myfile.txt|awk '{print $1}'))): вычислить количество строк, которые нужно удалить (т. Е. Все строки файла, кроме (последних) 100, которые нужно сохранить)
  • 1, $((..)) d: удалить все строки от первой до вычисленной строки

РЕДАКТИРОВАТЬ: так как вопрос был только что отредактирован, чтобы дать больше деталей, я включу эту дополнительную информацию в свой ответ. Добавлены факты:

  • конкретный размер должен оставаться в файле (10 000 байт)
  • каждая строка имеет определенный размер в байтах (300 байтов в примере)

Из этих данных можно рассчитать количество строк, которые останутся как «/», что в примере будет означать 33 строки. Термин оболочки для вычисления: $((size_to_remain / linesize)) (по крайней мере, в Linux, использующем Bash, результатом является целое число). Настроенная команда теперь будет выглядеть так:

# keep the start of the file (OPs question)
sed -i '34,$ d' myfile.txt
# keep the end of the file (my second example)
[ $(wc -l myfile.txt) -gt 33 ] && sed -i "1,33 d" myfile.txt

Поскольку размеры известны заранее, больше нет необходимости в вычислениях, встроенных в команду sed . Но для гибкости, внутри некоторого сценария оболочки можно использовать переменные.

Для условной обработки, основанной на размере файла, можно использовать следующую "тестовую" конструкцию:

[ "$(ls -lk $file | awk ' {print $5}')" -gt 100 ] &&

что означает: «если размер $file превышает 100kB, делайте ...» (ls -lk перечисляет размер файла в килобайтах в позиции 5, следовательно, awk используется для извлечения именно этого).

1

В предыдущих ответах можно избежать сложности sed/wc если использовать awk . Используя пример, предоставленный из OP (показывающий полные строки до 10000 байт):

awk '{i += (length() + 1); if (i <= 10000) print $ALL}' myfile.txt

Также показывает полную строку, содержащую 10000-й байт, если этот байт не находится в конце строки:

awk '{i += (length() + 1); print $ALL; if (i >= 10000) exit}' myfile.txt

Ответ выше предполагает:

  1. Текстовый файл содержит символ конца строки Unix (\n). Для текстовых файлов Dos/Windows (\r\n) измените length() + 1 на length() + 2
  2. Текстовый файл содержит только однобайтовый символ. Если есть многобайтовые символы (например, в среде Юникода), установите среду LC_CTYPE=C чтобы принудительно интерпретировать на уровне байтов.
0

Не найдя команды для этого, я написал быстрый скрипт (не тестировался):

#!/bin/sh

# Usage: $0 glob.* 25000
# where glob.* is a wildcard pattern and 25000 is the maximum number of bytes.

limit=20000
tmp=/tmp/trim
[[ "$2" == +([0-9]) ]] || limit=$2
limit=`expr $len + 1`
for file in $1;
do
    [[ `wc -c $file` -lt $limit ]] && continue
    head -c $file > $tmp
    sed '$d' $tmp
    $tmp > $file
done
-1

Я сделал что-то похожее с хвостом. Чтобы сохранить только последние 10000 строк в этом случае:

TMP=$(tail -n 10000 /path/to/some/file 2>/dev/null) && echo "${TMP}" > /path/to/some/file
-1

Вы можете использовать команду linux sed для удаления строк из файла. Следующая команда удаляет последнюю строку filename.txt:

sed '$d' filename.txt

С помощью awk или find вы можете искать шаблон, соответствующий вашей команде sed. Сначала вы ищите с помощью awk или находите файлы, которые хотите сократить, а затем вы можете удалить строки с помощью sed.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .