it-swarm.com.ru

Как я могу удалить первую строку текстового файла, используя скрипт bash/sed?

Мне нужно многократно удалять первую строку из огромного текстового файла, используя скрипт bash.

Прямо сейчас я использую sed -i -e "1d" $FILE - но удаление займет около минуты.

Есть ли более эффективный способ сделать это?

449
Brent

Попробуйте GNU tail :

tail -n +2 "$FILE"

-n x: просто напечатайте последние x строки. tail -n 5 выдаст вам последние 5 строк ввода. Знак + инвертирует аргумент и заставляет tail печатать что угодно, кроме первых строк x-1. tail -n +1 будет печатать весь файл, tail -n +2 все, кроме первой строки и т. д.

GNU tail намного быстрее, чем sed. tail также доступен в BSD, а флаг -n +2 одинаков для обоих инструментов. Проверьте FreeBSD или OS X man-страницы для получения дополнительной информации. 

Однако версия BSD может быть намного медленнее, чем sed. Интересно, как им это удалось; tail должен просто читать файл построчно, в то время как sed выполняет довольно сложные операции, включая интерпретацию скрипта, применение регулярных выражений и тому подобное.

Примечание: вы можете испытать желание использовать

# THIS WILL GIVE YOU AN EMPTY FILE!
tail -n +2 "$FILE" > "$FILE"

но это даст вам пустой файл. Причина в том, что перенаправление (>) происходит до того, как оболочка tail будет вызвана:

  1. Оболочка обрезает файл $FILE
  2. Shell создает новый процесс для tail
  3. Оболочка перенаправляет стандартный вывод процесса tail в $FILE
  4. tail читает из теперь пустого $FILE

Если вы хотите удалить первую строку внутри файла, вы должны использовать:

tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"

&& гарантирует, что файл не будет перезаписан при возникновении проблемы.

866
Aaron Digulla

Вы можете использовать -i для обновления файла без использования оператора «>». Следующая команда удалит первую строку из файла и сохранит ее в файл.

sed -i '1d' filename
119
amit

Для тех, кто работает в SunOS, не являющейся GNU, следующий код поможет:

sed '1d' test.dat > tmp.dat 
67
Nasri Najib

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

Но ваш вопрос страдает от той же проблемы, что и многие другие, в том смысле, что он предполагает решение. Если вы расскажете нам подробно что вы пытаетесь сделать, а не как , мы можем предложить лучший вариант.

Например, если это файл A, который обрабатывает какая-то другая программа B, одним из решений было бы не убрать первую строку, а изменить программу B для ее обработки по-другому.

Допустим, все ваши программы добавляют к этому файлу A, и программа B в настоящее время читает и обрабатывает первую строку перед ее удалением.

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

Затем в тихое время (полночь?) Он может выполнить специальную обработку файла A, чтобы удалить все обрабатываемые в данный момент строки и установить смещение обратно на 0.

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

16
paxdiablo

Вы можете отредактировать файлы на месте: просто используйте флаг Perl -i, например:

Perl -ni -e 'print unless $. == 1' filename.txt

Это заставляет первую строку исчезнуть, как вы просите. Perl нужно будет прочитать и скопировать весь файл, но он организует сохранение вывода под именем исходного файла.

9
alexis

Как сказал Пакс, вы, вероятно, не получите быстрее, чем это. Причина в том, что практически нет файловых систем, поддерживающих усечение с начала файла, поэтому это будет операция O (n), где n - размер файла. Что вы можете сделать намного быстрее, хотя перезаписать первую строку с таким же количеством байтов (возможно, с пробелами или комментарием), что может работать для вас в зависимости от того, что именно вы пытаетесь сделать (что это делает путь?).

8
Robert Gamble

sponge util избавляет от необходимости манипулирования временным файлом:

tail -n +2 "$FILE" | sponge "$FILE"
6
agc

Если вы хотите изменить файл на месте, вы всегда можете использовать оригинальный ed вместо его s treaming наследника sed:

ed "$FILE" <<<$'1d\nwq\n'
4
Mark Reed

Как насчет использования csplit?

man csplit
csplit -k file 1 '{1}'
3
crydo

Может использовать vim для этого:

vim -u NONE +'1d' +'wq!' /tmp/test.txt

Это должно быть быстрее, так как vim не будет читать весь файл при обработке.

3
Hongbo Liu

должны показывать строки кроме первой строки:

cat textfile.txt | tail -n +2
2
serup

Если вы хотите восстановить после сбоя, вы можете просто создать файл, который имеет то, что вы сделали до сих пор.

if [[ -f $tmpf ]] ; then
    rm -f $tmpf
fi
cat $srcf |
    while read line ; do
        # process line
        echo "$line" >> $tmpf
    done
0
Tim

Поскольку кажется, что я не могу ускорить удаление, я думаю, что хорошим подходом может быть обработка файла в пакетах примерно так:

While file1 not empty
  file2 = head -n1000 file1
  process file2
  sed -i -e "1000d" file1
end

Недостатком этого является то, что если программа будет убита в середине (или если там будет какой-то плохой sql - что приведет к смерти или блокировке части процесса), будут строки, которые либо пропускаются, либо обрабатываются дважды ,.

(file1 содержит строки кода SQL)

0
Brent

Вы можете легко сделать это с:

cat filename | sed 1d > filename_without_first_line

в командной строке; или чтобы окончательно удалить первую строку файла, используйте режим sed на месте с флагом -i:

sed -i 1d <filename>
0
Ingo Baab