Как удалить каждую вторую строку из файла?

25

Файл:

Data inserted into table. Total count 13
No error occurred
Data inserted into table. Total count 45
No error occurred
Data inserted into table. Total count 14
No error occurred
Data inserted into table. Total count 90
No error occurred

Ожидаемый выходной файл:

Data inserted into table. Total count 13
Data inserted into table. Total count 45
Data inserted into table. Total count 14
Data inserted into table. Total count 90

Я хочу, чтобы вывод выглядел так: каждая вторая строка будет удалена, но между строками не будет пропуска.

pmaipmui
источник
5
Вы хотите удалить каждую вторую строку или все строки, которые содержат «Ошибка не возникла» ? Что, если в двух последовательных строках было написано «Нет ошибки» ?
Тулаинс Кордова
1
@ user1598390 Я думаю ... в этом случае grep -v "No error occurred" fileэта команда должна работать ... на что ответил @paul. В выходном файле не будет строк, содержащих «Нет ошибок».
pmaipmui
1
Тогда название вопроса вводит в заблуждение.
Тулаинс Кордова

Ответы:

36

С sed:

sed -e n\;d <file

С POSIX awk:

awk 'FNR%2' <file

Если у вас есть старше awk(как oawk), вам нужно:

oawk 'NR%2 == 1' <file

С ex:

$ ex file <<\EX
:g/$/+d
:wq!
EX

отредактируем файл на месте.

  • g пометить глобальную команду
  • /$/ соответствовать каждой линии
  • +d удалить следующую строку
  • wq! сохранить все изменения

Этот подход разделяет тот же идеал с sedподходом, удаляя каждую следующую строку текущей строки, начиная со строки 1.

С perl:

perl -ne 'print if $. % 2' <file

и perl6:

perl6 -ne '.say if $*IN.ins % 2' <file
perl6 -ne '.say if ++$ % 2' <file
cuonglm
источник
Да ... он работает ... :) ... первый работает .... я тоже пробовал второй ... он говорит `awk: синтаксическая ошибка line1 awk: вылетает около строки 1 '
pmaipmui
sed -en \; d <file ~ Да, работает @cuonglm ...
pmaipmui
1
Я предполагаю, что вы использовали n\;dвместо того, 'n;d'чтобы сохранить драгоценный символ, но эта логика выходит за рамки, когда вы без необходимости используете -eпереключатель и перенаправление файлов <!
Том Фенек
1
@ Geek: Это просто более короткая версия sed -e 'n;d', за исключением одного персонажа.
Cuonglm
1
@Geek: nкоманда записать пространство шаблона в стандартный вывод, если он -nбыл использован, а затем заменить пространство шаблона следующей строкой. Здесь каждая нечетная строка будет напечатана n, четная строка затем будет считана в пространство шаблона, но немедленно dудалена командой`.
Cuonglm
62

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

grep -v "No error occurred" file

Он может работать как фильтр, вы можете добавить больше шаблонов мусора и улучшить результат.

Павел
источник
9
+1 за указание на то, что иногда важна вторая строка!
Каз Вулф
12

В связи с вопросом, с GNU sed:

sed '0~2d' file

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

sed '/Data/! d' file

или с тем же результатом

sed '/No error/d' file
Костас
источник
Файл sed '/ No error / d' ~ дает желаемый результат @Costas
pmaipmui
5
Обратите внимание, что последние два - запутанные способы написания grep Dataиgrep -v 'No error'
Стефан Шазелас
5

Вот способ использования sed:

sed -n 'p;n' filename

Другой способ с GNU sed:

sed -n '1~2p' filename

Вывод вышеуказанных команд:

Data inserted into table. Total count 13
Data inserted into table. Total count 45
Data inserted into table. Total count 14
Data inserted into table. Total count 90
serenesat
источник
Что вы имеете в виду, когда говорите shortest way using sed?
cuonglm
В чем причина в gкоманде? sed -n 'p;n'достаточно.
Костас
@cuonglm: я хочу сказать, простой способ сделать. Кстати убрал это слово. :)
Серенесать
@ Костас: Спасибо! Только что проверил, работает без g. снял г с команды. :)
серенесать
4

Вы можете попробовать с awk:

awk 'NR % 2 != 0' file

или вы можете печатать только строки, содержащие Data inserted:

awk '$0 ~ /Data inserted/' file
taliezin
источник
Я попробовал оба ответа, и оба работают ... :)
pmaipmui
3

Другой ответ, вы можете использовать vi / vim!

qdjddq

И тогда, если ваш файл был 500 строк (например) типа

250 @ д

А потом написать и выйти типа

:Икс

Или, если что-то пойдет не так, и вы не хотите сохранять:

: Д!

Объяснение:

q      #Start Recording
 d     #Put the recording into register 'd'
  j    #Move the cursor down
   dd  #Delete the line
     q #Stop recording


250    #Number of repeats
   @d  #Playback the recording in register 'd'.
DJMcMayhem
источник
2

Вот совсем другой способ сделать это:

< file paste - - | cut -f1

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

< file paste -d: - - | cut -d: -f1
Цифровая травма
источник
1
Я имел это в виду, когда впервые увидел вопрос ... Было бы интересно провести тест скорости sedс огромным файлом (например, 20 млн строк). В любом случае, +1, но на самом деле, чтобы избежать головной боли, выберите разделитель, который вряд ли встречается в текстовом файле, например $'\002'...
don_crissti
@don_crissti да, использование непечатаемого символа для разделителя - хорошая идея. И да, это заметно быстрее, чем решение sed. Я создал тестовый файл с seq 100000000 > 100mil.txt. paste|cutРаствор закончил примерно 7,5 секунды, против почти 12 для sedраствора. Кажется, чтобы быть повторяемым. grepсамый быстрый, хотя Ubuntu 14.04 со стандартными инструментами GNU.
Цифровая травма
Да, paste+ cutсильно оптимизированы для своей работы, поэтому неудивительно, что их комбинация чертовски быстра ...
don_crissti
1

Другой вариант (короче)

sed 'n; d' file
Майкл Даррант
источник
3
Это длиннее, чем у меня sed n\;d, добавление -eэто только моя привычка.
cuonglm
0

Это также решает проблему, хотя и немного медленнее:

vim -c "%normal jdd" -c "wq" file
FloriOn
источник