Як знайти лінії, що відповідають шаблону, і видалити їх?


14

У файлі з великою кількістю рядків я хочу видалити рядки, з яких починається HERE IT IS.

Як це зробити за допомогою лише інструментів командного рядка?


2
Хоча трохи нетрадиційно, ви можете використовувати vimтак vim '+g/^HERE IT IS/d' +wq test.txt
Дорнобрук

@Doorknob, дякую, що вказали на це. Насправді я на шляху до використання vim
micgeronimo

Відповіді:


29

Спробуйте sed:

sed -i '/^HERE IT IS/d' <file>

ПОПЕРЕДЖЕННЯ: Краще взяти резервну копію при використанні -iперемикача sed:

sed -i.bak '/^HERE IT IS/d' <file>

Оригінальний файл залишиться таким же, як <file>.bakі модифікований файл <file>.


Як я можу вставити символ нового рядка після зібраного рядка і записати в новий рядок?
micgeronimo

2
sed -i 's/^HERE IT IS/HERE IT IS\n/' <file>
heemayl

1
@micgeronimo: радимо допомогти. Перевірте, будь ласка, мої зміни.
heemayl

6
@micgeronimo спробуйте задати питання, на яке ви дійсно хочете відповісти, у своєму початковому запитанні (пам’ятайте, що ви можете його відредагувати), а не через коментарі, які можуть бути очищені / видалені. Можна використовувати sed '/^HERE IT IS/G' file.
steeldriver

1
Використання sed є таким професійним.
LakshyaAg

18

Окрім дуже хороших grepта sedотриманих відповідей, ось деякі інші інструменти, які можуть зробити те саме:

  • Кілька способів Perl:

    perl -ne '/^HERE IT IS/ || print' file > newfile
    perl -ne 'print if !/^HERE IT IS/' file > newfile
    perl -ne 'print unless /^HERE IT IS/' file > newfile
    

    Ви можете додати -iкомутатор до будь-якого з прикладів, щоб змінити файл на місці:

    perl -i.bak -ne '/^HERE IT IS/ || print' file        
    
  • (ж) awk

    awk '!/^HERE IT IS/' file > newfile
    

    Новіші версії (4.1.1 і новіші) GNU awk(за замовчуванням awkв Linux) також можуть редагувати файл на місці:

    gawk -i inplace  '!/^HERE IT IS/' file
    
  • Shell ( bash, zsh, ksh, ймовірно , інші). Це щось нерозумно, але це можна зробити, але інші інструменти краще.

    while IFS= read -r line; do 
      [[ $line =~ ^"HERE IT IS" ]] || printf "%s\n" "$line"
    done < file > newfile
    

1
Ти просто демонструєш! ;-) (але ти отримав нагороду, тому що це розумно, і я багато чому навчився, і той bashзробив мене LOL)
Fabby

bash слід використовувати printf "%s\n" "$line": цитуючи $ line, щоб зберегти пробіли та уникати деяких ехо-проблем (інтерпретація спеціальних символів тощо). і уникає необхідності додавати --теж.
Олів'є Дулак,

@OlivierDulac досить справедливо. Я не хотів ускладнювати для випадків бахроми , але з тих пір додав Cuanglm IFS=і -r, я можу також пройти весь шлях і зробити його стійким.
тердон

@terdon: це все , для кращого блага ^^ (і я +1 вже, хоча, як це дуже інформативно для початківців)
Олів'є Dulac

2
@OlivierDulac Я можу запевнити, що якби я розміщував повідомлення на Unix та Linux, я використовував би printf, IFS =, -r та цитую :). Я часто спрощую речі для аудиторії АС, які часто менш комфортні з командним рядком.
тердон

13

Я б використав grepдля їх фільтрації. Наприклад :

grep -v "^HERE IT IS" infile > outfile

Потім поверніться назад до інфайлу.


Розумне мислення
Анвар

5

sed це, безумовно, шлях.

Ця незначна модифікація команди @heemayl дала вам видалити рядок, незалежно від того, чи використовується той самий випадок у шаблоні чи ні, через I у посиланні на шаблон.

sed -i '/HERE IT IS/Id' <file>

Якщо у вас було декілька файлів у каталозі, на якому ви хотіли це зробити, ви можете комбінувати його з таким чином знайти.

find . -maxdepth 1 -type f -exec sed -i.bak '/HERE IT IS/Id' {} +

Параметр maxdepth означає, що це не повторюватиметься в каталогах.


4

Ще один варіант пітона:

#!/usr/bin/env python3
[print(l, end = "") for l in open(f).readlines() if not l.startswith("HERE IT IS")]

Де f - шлях до файлу, між лапками.


4

Греп

grep -P '^(?!HERE IT IS)' file

(?!HERE IT IS)негативне твердження lookahead, яке змушує механізм регулярного вирівнювання відповідати всій початковій межі лінії ( яка зазвичай відповідає^ ), лише якщо за нею не йде рядокHERE IT IS

пітон

#!/usr/bin/python3
import sys
fil = sys.argv[1]
with open(fil) as f:
    for line in f:
        if not line.startswith('HERE IT IS'):
            print(line, end="")

Збережіть скрипт у файлі, скажімо, script.pyа потім запустіть його за допомогою команди нижче на терміналі.

python3 script.py infile

ви могли б використовувати там регулярний вираз [print(l, end = "") for l in open(fil).readlines() if not re.match("HERE IT IS", l)], але це не набагато ефективніше, ніж startswith. Мені було цікаво, як [print(l, end = "") for l in open(f).readlines() if not l.startswith("HERE IT IS")]не вдасться отримати результат у списку.
Avinash Raj

Перший раз, коли я наткнувся на це, мені це здалося дивним. Він генерує команду друку (або будь-яку дію, яку ви хочете виконати з нею) для всіх елементів у визначеному списку.
Яків Влійм

Відміняючи це, просто заради забави :)
Яків Влійм

1

Ви можете використовувати Vim в режимі Ex:

ex -sc 'g/^HERE IT IS/d' -cx file
  1. g глобальний пошук

  2. d видалити

  3. x зберегти і закрити

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.