Знайдіть і замініть текст у файлі за допомогою команд


Відповіді:


1053
sed -i 's/original/new/g' file.txt

Пояснення:

  • sed = Редактор потоку
  • -i = на місці (тобто зберегти назад у вихідний файл)
  • Командний рядок:

    • s = команда заміщення
    • original = регулярний вираз, що описує слово, яке потрібно замінити (або просто саме слово)
    • new = текст для заміни
    • g = глобальний (тобто замінити все, а не лише перше виникнення)
  • file.txt = ім'я файлу


3
@Akiva Якщо ви включите у свій пошук спеціальні символи зразка, sedвони відповідають їм. Додайте -rпрапор, якщо ви хочете замість цього використовувати розширені RE.
cscarney

32
@mcExchange Якщо конкретно потрібний /символ, то ви можете просто використовувати якийсь інший символ як роздільник (наприклад 's_old/text_new/text_g'). В іншому випадку ви можете поставити \ перед будь-яким із них, $ * . [ \ ^щоб отримати буквальний характер.
cscarney

3
@BrianZ Що стосується файлової системи, то вихід sed - це новий файл з такою ж назвою. Це одна з часто повідомляються про помилки, які не є помилками
cscarney

16
Команду OSX sed -i '.bak' 's/original/new/g' file.txtможна також запустити з розширенням нульової довжини sed -i '' 's/original/new/g' file.txt, що не створить резервного копіювання.
Кірк

19
Користувачам MacOS доведеться додати '' "після -i як параметр для -i ed.gs/2016/01/26/os-x-sed-invalid-command-code, щоб файл був перезаписаний.
geoyws

32

Існує ряд різних способів зробити це. Один використовує sedі Regex. SED - це редактор потоку для фільтрації та перетворення тексту. Один з таких прикладів:

marco@imacs-suck: ~$ echo "The slow brown unicorn jumped over the hyper sleeping dog" > orly
marco@imacs-suck: ~$ sed s/slow/quick/ < orly > yarly
marco@imacs-suck: ~$ cat yarly
The quick brown unicorn jumped over the hyper sleeping dog

Інший спосіб , який може мати більше сенсу , ніж < strinта > stroutє з трубами!

marco@imacs-suck: ~$ cat yarly | sed s/unicorn/fox/ | sed s/hyper/lazy/ > nowai
marco@imacs-suck: ~$ cat nowai 
The quick brown fox jumped over the lazy sleeping dog

6
зауважте, що catв cat file | sed '...'- непотрібно. Можна прямо сказати sed '...' file.
fedorqui

1
Дійсно, це може бути зменшено ще більше: sed -i'.bak' -e 's/unicorn/fox/g;s/hyper/brown/g' yarlyзніматимете файл та зробимо 2 зміни на місці, роблячи резервну копію. Використовуючи time bash -c "$COMMAND"час, це дозволяє припустити, що ця версія в 5 разів швидша.
pbhj

23

Існує безліч способів цього досягти. Залежно від складності того, що намагається досягти із заміною рядків, та залежно від інструментів, з якими користувач знайомий, деякі методи можуть віддавати перевагу більше, ніж інші.

У цій відповіді я використовую простий input.txtфайл, який ви можете використовувати для тестування всіх наведених тут прикладів. Вміст файлу:

roses are red , violets are blue
This is an input.txt and this doesn't rhyme

БАШ

Bash насправді не призначений для обробки тексту, але прості підстановки можна зробити за допомогою розширення параметрів , зокрема тут ми можемо використовувати просту структуру ${parameter/old_string/new_string}.

#!/bin/bash
while IFS= read -r line
do
    case "$line" in
       *blue*) printf "%s\n" "${line/blue/azure}" ;;
       *) printf "%s\n" "$line" ;;
    esac
done < input.txt

Цей невеликий сценарій не робить заміни на місці, це означає, що вам доведеться зберегти новий текст у новому файлі та позбутися від старого файлу, або mv new.txt old.txt

Побічна примітка: якщо вам цікаво, чому while IFS= read -r ; do ... done < input.txtвін використовується, це в основному спосіб оболонки читання файлів по черзі. Дивіться це для довідки.

AWK

AWK, будучи утилітою для обробки тексту, цілком підходить для такого завдання. Він може робити прості заміни та значно вдосконаленіші, засновані на регулярних виразах . Він забезпечує дві функції: sub()і gsub(). Перший замінює лише перший випадок, а другий - замінює входи цілим рядком. Наприклад, якщо у нас є рядок one potato two potato, це буде результат:

$ echo "one potato two potato" | awk '{gsub(/potato/,"banana")}1'
one banana two banana

$ echo "one potato two potato" | awk '{sub(/potato/,"banana")}1'                                      
one banana two potato 

AWK може взяти вхідний файл як аргумент, тому робити те саме input.txt, що було б легко:

awk '{sub(/blue/,"azure")}1' input.txt

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

awk '{sub(/blue/,"azure")}1' input.txt > temp.txt && mv temp.txt input.txt

СЕД

Sed - редактор рядків. Він також використовує регулярні вирази, але для простих підстановок достатньо зробити:

sed 's/blue/azure/' input.txt

Що хорошого в цьому інструменті, це те, що він має місцеве редагування, яке ви можете ввімкнути -iпрапором.

Perl

Perl - це ще один інструмент, який часто використовується для обробки тексту, але це загальна мова і використовується в мережах, системному адмініструванні, настільних додатках та багатьох інших місцях. Він запозичив безліч понять / особливостей з інших мов, таких як C, sed, awk та інші. Просту заміну можна зробити так:

perl -pe 's/blue/azure/' input.txt

Як і sed, perl також має прапор -i.

Пітон

Ця мова є дуже універсальною і також використовується в широкому спектрі застосувань. Він має багато функцій для роботи з рядками, серед яких є replace(), тому, якщо у вас є така змінна var="Hello World", ви можете це зробитиvar.replace("Hello","Good Morning")

Простий спосіб зчитувати файл і замінити рядок у ньому буде таким:

python -c "import sys;lines=sys.stdin.read();print lines.replace('blue','azure')" < input.txt

З Python, однак, вам також потрібно вивести новий файл, що ви також можете зробити з самого сценарію. Наприклад, ось такий простий:

#!/usr/bin/env python
import sys
import os
import tempfile

tmp=tempfile.mkstemp()

with open(sys.argv[1]) as fd1, open(tmp[1],'w') as fd2:
    for line in fd1:
        line = line.replace('blue','azure')
        fd2.write(line)

os.rename(tmp[1],sys.argv[1])

Цей скрипт повинен викликатися input.txtаргументом командного рядка. Точною буде команда для запуску сценарію python з аргументом командного рядка

 $ ./myscript.py input.txt

або

$ python ./myscript.py input.txt

Звичайно, переконайтеся, що він ./myscript.pyзнаходиться у вашому поточному робочому каталозі, і, перш за все, переконайтеся, що він встановлений у виконанніchmod +x ./myscript.py

Python також може мати регулярні вирази, зокрема, є reмодуль, який має re.sub()функцію, яку можна використовувати для більш вдосконалених замін.


1
Приємна збірка! Ще один можливий спосіб, який не згадується тут, - це використання trкоманди в unix
Tapajit Dey

1
@TapajitDey Так, tr це ще один чудовий інструмент, але зауважте, що він призначений для заміни наборів символів (наприклад, це tr abc cdeбуло б перекладом aна c, bна d. Це трохи відрізняється від заміни цілих слів, як з sedабоpython
Сергій Колодяжний

22

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

ex -s -c '%s/OLD/NEW/g|x' file
  1. % виберіть усі рядки

  2. s замінник

  3. g замінити всі екземпляри у кожному рядку

  4. x написати, якщо зміни були внесені (вони були) та вийти


21

Через команду gsub awk,

awk '{gsub(/pattern/,"replacement")}' file

Приклад:

awk '{gsub(/1/,"0");}' file

У наведеному вище прикладі всі 1 замінюються на 0 незалежно від стовпця, де він знаходиться.


Якщо ви хочете зробити заміну в певному стовпці, зробіть це так,

awk '{gsub(/pattern/,"replacement",column_number)}' file

Приклад:

awk '{gsub(/1/,"0",$1);}' file

Він замінює 1 на 0 лише в першому стовпці.

Через Perl,

$ echo 'foo' | perl -pe 's/foo/bar/g'
bar

Я використовував це на терміналі MacOS, і він нічого не робив ...
Джим,

Тестували на Alpine Linux (у контейнері Docker) і не отримали вихід
Salathiel Genèse

@ SalathielGenèse чого ти намагаєшся досягти?
Авінаш Радж

Я переглядаю файл із inotifywaitпрограмою under shenv та повідомляю про дані у форматі CSV (оскільки користувацький формат є помилковим). Потім я зрозумів, що немає простого способу обробки CSV-документа в скриптах оболонки ... І мені це дуже легко. Тому я запустив досить простий сценарій для розбору та повідомлення CSV. Я прочитав специфікацію CSV і помітив, що вона досконаліша, ніж я очікувала, і підтримую багаторядне значення, загорнуте у подвійні лапки. Я покладався на sedтокенізацію, але незабаром зрозумів, що навіть те, що sedназивати мультилініями, до двох ліній. Що робити, якщо одне з моїх значень CSV охоплює більше двох рядків?
Салатієль Генезе

краще поставити свою проблему як питання.
Авінаш Радж

8

sedє s Tream ред itor , в тому , що ви можете використовувати |(труби) для передачі стандартних потоків (STDIN і STDOUT в зокрема) шляхом sedі змінювати їх програмно на льоту, що робить його зручним інструментом в філософії традиції Unix; але також можна редагувати файли безпосередньо, використовуючи -iвказаний нижче параметр.
Розглянемо наступне :

sed -i -e 's/few/asd/g' hello.txt

s/використовується для s заміну знайденого виразу за fewдопомогою asd:

Нечисленні, сміливі.


Адд, хоробрий.

/gрозшифровується як "глобальний", що означає робити це для всієї лінії. Якщо ви вимкнете /gs/few/asd/, завжди має бути три косої риски незалежно від того) і fewз’являється двічі в одному рядку, лише перший fewзмінюється на asd:

Кілька чоловіків, кілька жінок, хоробрі.


Чоловіки Асд, нечисленні жінки, сміливі.

Це корисно за деяких обставин, як, наприклад, зміна спеціальних символів на початку рядків (наприклад, заміна символів більших за символи, які деякі використовують для цитування попереднього матеріалу в потоках електронної пошти горизонтальною вкладкою, залишаючи пізніше в рядку цитовану алгебраїчну нерівність недоторканою), але у своєму прикладі, де ви вказуєте, що де завгодно, few його слід замінити, переконайтесь, що у вас це є /g.

Наступні два варіанти (прапори) об'єднані в один -ie:

-iпараметр використовується для редагування i n місця у файлі hello.txt.

-eУ цьому випадку опція вказує команду e xpression / команда для запуску s/.

Примітка. Важливо використовувати -i -eдля пошуку / заміни. Якщо це зробити -ie, ви створюєте резервну копію кожного файлу з доданою буквою 'e'.


2

Ви можете зробити так:

locate <part of filaname to locate> | xargs sed -i -e "s/<Old text>/<new text>/g" 

Приклади: щоб замінити всі входження [logdir ',' '] (без []) на [logdir', os.getcwd ()] у всіх файлах, які є результатом команди locate, виконайте:

ex1:

locate tensorboard/program.py | xargs sed -i -e "s/old_text/NewText/g"

ex2:

locate tensorboard/program.py | xargs sed -i -e "s/logdir', ''/logdir', os.getcwd()/g"

де [tensorboard / program.py] - файл для пошуку


Привіт. Ваш вибір рядків ( logdir', ''-> /logdir', os.getcwd()) робить цю відповідь важкою для розбору. Крім того, варто уточнити, що ваша відповідь спочатку знаходить файли для використання sed, оскільки це не є частиною питання.
mwfearnley

Привіт, ця відповідь одночасно шукає та замінює все, якщо воно знайшло <старий текст> у файлі.
Nguyễn Tuấn Anh

Я вибираю цю відповідь для всіх, хто використовує тензорну дошку в керах, які хочуть змінити команду з: tensorboard --logdir = '/ шлях / до / журналу / папки /', щоб використовувати: тільки тензор, протягом перебування в папці журналів. це дуже зручно
Nguyễn Tuấn Anh
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.