Як видалити з текстового файлу всі рядки, що містять певний рядок?


Відповіді:


2758

Щоб видалити рядок і роздрукувати вихідний стандарт у стандартному режимі:

sed '/pattern to match/d' ./infile

Щоб безпосередньо змінити файл - не працює з BSD sed:

sed -i '/pattern to match/d' ./infile

Те саме, але для BSD sed (Mac OS X і FreeBSD) - не працює з sed GNU:

sed -i '' '/pattern to match/d' ./infile

Щоб безпосередньо змінити файл (і створити резервну копію) - працює з BSD і GNU sed:

sed -i.bak '/pattern to match/d' ./infile

13
Дякуємо, але це, здається, не видаляє його з файлу, а просто роздрукує вміст текстового файлу без цього рядка.
Помаранчевий годинник

115
@A Clockwork: так, вам потрібно переспрямувати вихід або на новий файл з чимось на зразок, sed '/pattern to match/d' ./infile > ./newfileабо якщо ви хочете внести редагування на місці, тоді ви можете додати -iпрапор до sed як in sed -i '/pattern to match/d' ./infile. Зауважте, що -iпрапор вимагає sed GNU і не є портативним
SiegeX

16
Для деяких ароматів sed; прапор "-i" sed вимагав надати розширення. (напр. sed -i.backup '/pattern to match/d' ./infile) Мені доводилося змінювати зміни на місці.
avelis

9
@SiegeX Ще краще, не застосовуйте такі команди, як sedдо будь-яких файлів, які не контролюються версією.
MatrixFrog

84
Ще одна примітка для користувачів Mac OS X: чомусь прапор -i вимагає передавати аргумент, навіть якщо це лише порожня рядок sed -i '' '/pattern/d' ./infile.
geerlingguy

631

Окрім цього, існує багато інших способів видалення рядків із певним рядком sed :

AWK

awk '!/pattern/' file > temp && mv temp file

Ruby (1.9+)

ruby -i.bak -ne 'print if not /test/' file

Perl

perl -ni.bak -e "print unless /pattern/" file

Оболонка (удар 3.2 і пізніші)

while read -r line
do
  [[ ! $line =~ pattern ]] && echo "$line"
done <file > o
mv o file

GNU grep

grep -v "pattern" file > temp && mv temp file

І звичайно sed(друк оберненого відбувається швидше, ніж фактичне видалення):

sed -n '/pattern/!p' file

4
як видалити певний рядок із візерунком, а також рядок безпосередньо над ним? Я маю штраф із тисячами таких рядків між різними даними.
oortcloud_domicile

1
У OS / X варіація оболонки не зберігає провідні простори, але варіант grep -v добре працював для мене.
Paul Beusterien

13
sedприклад має різну поведінку, він тільки відбирає! це має бути щось на кшталт sed -n -i '/pattern/!p' file.
цезарсол

8
Версія grep не працює, коли кожен рядок відповідає шаблону. Краще робити: grep -v "pattern" file > temp; mv temp fileце може стосуватися деяких інших прикладів залежно від повернутого значення.
Кріс Мейс

1
"друк оберненого відбувається швидше, ніж фактичне видалення" - Не на моїй машині (2012 MacBook Air, OS X 10.13.2). Створити файл: seq -f %f 10000000 >foo.txt. sed d: time sed -i '' '/6543210/d' foo.txtреальні 0м9.294с. sed! p: time sed -i '' -n '/6543210/!p' foo.txtреальні 0м13.671с. (Для менших файлів різниця більша.)
jcsahnwaldt каже GoFundMonica

252

Ви можете використовувати sed для заміни рядків у файлі. Однак, здається, це набагато повільніше, ніж використання grep для зворотного у другий файл, а потім переміщення другого файлу над оригіналом.

напр

sed -i '/pattern/d' filename      

або

grep -v "pattern" filename > filename2; mv filename2 filename

Перша команда все-таки займає 3 рази більше часу на моїй машині.


19
Оголошення вашої відповіді теж тому, що ви спробували порівняння ефективності!
anuragw

4
+1 для пропонування опції перезаписати поточний файл рядком grep.
Рюк

2
Друге рішення "grep" також краще для великих файлів
simoes

3
Мені цікаво, якою була б різниця у виконанні, якби вона булаsed '/pattern/d' filename > filename2; mv filename2 filename
Піт

8
(використовуючи / usr / share / dict / words ubuntu) grep та mv: 0.010s | sed на місці: 0,197s | sed та mv: 0,031s
ReactiveRaven

77

Найпростіший спосіб зробити це за допомогою GNU sed:

sed --in-place '/some string here/d' yourfile

55
Зручна порада для інших, хто натрапляє на цю тему запитань і запитань і не є новим для сценаріїв оболонок: Короткі параметри є чудовими для одноразового використання в командному рядку, але в сценаріях слід віддавати перевагу довгим варіантам, оскільки вони є більш читабельними.
Денніс

3
+1 - прапор - in-place Мені потрібно перевірити це на захищених правах файлах. (Доводиться робити чистку користувачів.)
Bee Kay

8
Зауважте, що довгий варіант доступний лише на GNU sed. Користувачам Mac та BSD потрібно буде встановити gsed, щоб зробити це таким чином.
Метт

Ще одна порада: якщо ваш регекс не збігається, спробуйте вибрати -rваріант (або -E, залежно від версії). Це дозволяє використовувати регулярні вирази метасимволов +, ?, {...}і (...).
rjh

Це правильна відповідь, коли на вашому диску немає більше місця і ви не можете скопіювати текст в інший файл. Цією командою виконайте те, що було поставлено під сумнів?
ferreirabraga

38

Ви можете розглянути можливість використання ex(який є стандартним редактором на основі команд Unix):

ex +g/match/d -cwq file

де:

  • +виконує задану команду Ex ( man ex), те саме, -cщо виконує wq(записувати та виходити)
  • g/match/d- Команда Ex для видалення рядків із заданими match, див .: Потужність g

Вищенаведений приклад - це сумісний з POSIX метод редагування файлів на місці відповідно до цієї публікації за специфікаціями Unix.SE та POSIX дляex .


Різниця в sedтому, що:

sedце S трем ED ED itor , а не редактор файлів. BashFAQ

Якщо вам не сподобається нерепортажний код, накладні введення / виведення та деякі інші погані побічні ефекти. Отже, деякі параметри (наприклад, на місці / -i) є нестандартними розширеннями FreeBSD і можуть бути недоступні для інших операційних систем.


5
це здорово ... коли я роблю man exце дає мені людина за vimце , здається , exє частиною Vim ... якщо я зрозумів правильно , що означає , що синтаксис шаблону для matchє vimregex.com , який схожий , але відрізняється від POSIX і PCRE смаків?
Анентроп

1
:g є сумісною з POSIX командою з деякими незначними відмінностями . Я припускаю, що PCRE був заснований на цьому.
kenorb

16

Я боровся з цим на Mac. Плюс, мені потрібно було це зробити, використовуючи змінну заміну.

Тому я використав:

sed -i '' "/$pattern/d" $file

де $fileфайл, де потрібно видалення та$pattern є шаблон, який слід зіставити для видалення.

Я вибрав ''із цього коментаря .

Тут слід зазначити використання подвійних лапок в "/$pattern/d". Змінна не працюватиме, коли ми використовуємо одинарні лапки.


3
Mac sedвимагає параметр після -i, тому якщо ви не хочете створювати резервну копію, вам все одно потрібно додати порожній рядок:-i ''
wisbucky

Для використання оболонок sed -i "/$pattern/d" $file. Спасибі за вашу відповідь.
ashwaqar

14

Я зробив невеликий орієнтир з файлом, який містить приблизно 345 000 рядків. Шлях, grepздається, приблизно в 15 разів швидший, ніж sedметод у цьому випадку.

Я спробував як з налаштуванням LC_ALL = C, так і без нього, схоже, помітно не змінити таймінги. Рядок пошуку (CDGA_00004.pdbqt.gz.tar) десь посередині файлу.

Ось команди та таймінги:

time sed -i "/CDGA_00004.pdbqt.gz.tar/d" /tmp/input.txt

real    0m0.711s
user    0m0.179s
sys     0m0.530s

time perl -ni -e 'print unless /CDGA_00004.pdbqt.gz.tar/' /tmp/input.txt

real    0m0.105s
user    0m0.088s
sys     0m0.016s

time (grep -v CDGA_00004.pdbqt.gz.tar /tmp/input.txt > /tmp/input.tmp; mv /tmp/input.tmp /tmp/input.txt )

real    0m0.046s
user    0m0.014s
sys     0m0.019s

На якій платформі ви знаходитесь? Які версії sed / perl / grep ви використовуєте?
hagello

Я використовую платформу Linux (Gentoo). Версія sed - це GNU sed v 4.2.2, версія perl perl 5 (я не можу сказати, яку редакцію я використовував під час тесту), а grep (GNU) - версія 3.0.
Ядзя

14

Ви також можете скористатися цим:

 grep -v 'pattern' filename

Тут -vбуде надруковано лише інший, ніж ваш візерунок (це означає перевернути відповідність).


Як я можу видалити рядки з каталогу, які містять певний рядок
namannimmo

13

Щоб отримати такий результат, grepви можете зробити це:

echo "$(grep -v "pattern" filename)" >filename

4
Це добре тільки для bashоболонки або подібного (не tcsh).
відправити


4
perl -i    -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3

Перша команда редагує файл (и) inplace (-i).

Друга команда робить те саме, але зберігає копію чи резервну копію вихідних файлів, додаючи .bk до імен файлів (.bk можна змінити на будь-що).



2

На всякий випадок, якщо хтось захоче зробити це для точних відповідностей рядків, ви можете використовувати -wпрапор у великій точці - w для цілого. Це, наприклад, якщо ви хочете видалити рядки, які мають число 11, але збережіть рядки з номером 111:

-bash-4.1$ head file
1
11
111

-bash-4.1$ grep -v "11" file
1

-bash-4.1$ grep -w -v "11" file
1
111

Він також працює з -fпрапором, якщо ви хочете виключити відразу кілька точних шаблонів. Якщо "чорний список" - це файл з кількома шаблонами у кожному рядку, який потрібно видалити з "файла":

grep -w -v -f blacklist file

Трохи оману. -w, --word-regexp Select only those lines containing matches that form whole words.vs.-x, --line-regexp Select only those matches that exactly match the whole line. For a regular expression pattern, this is like parenthesizing the pattern and then surrounding it with ^ and $.
Сай


0

щоб показати оброблений текст у консолі

cat filename | sed '/text to remove/d' 

щоб зберегти оброблений текст у файл

cat filename | sed '/text to remove/d' > newfile

щоб додати інформацію про оброблений текст до наявного файлу

cat filename | sed '/text to remove/d' >> newfile

щоб обробити вже оброблений текст, у цьому випадку видаліть більше рядків того, що було видалено

cat filename | sed '/text to remove/d' | sed '/remove this too/d' | more

| moreпокаже текст шматків однієї сторінки за один раз.


0

Ви можете використовувати старий добрий edдля редагування файлу аналогічно відповіді, що використовується ex. Велика різниця в цьому випадку полягає в тому, що він edприймає свої команди за допомогою стандартного введення, а не як аргументи командного рядка, як exможуть. Використовуючи його в сценарії, звичайним способом для цього є використання printfдля передачі команд на нього:

printf "%s\n" "g/pattern/d" w | ed -s filename

або з гередоком:

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