Замініть цілий рядок, що містить рядок, використовуючи Sed


319

У мене є текстовий файл, який має певний рядок на кшталт

sometext sometext sometext TEXT_TO_BE_REPLACED sometext sometext sometext

Мені потрібно замінити весь рядок вище

This line is removed by the admin.

Ключове слово для пошуку є TEXT_TO_BE_REPLACED

Для цього мені потрібно написати сценарій оболонки. Як я можу досягти цього за допомогою sed?


@Scharron Я спробував sed -rne 's / (TEXT_TO_BE_REPLACED) \ s + \ w + / \ 1 yyy / xxx', але це просто замінить yyy на xxx у рядку, якщо такий є yyy. У моєму випадку текст не виправлений ... все, що у мене є, TEXT_TO_BE_REPLACED.
Рахул

це не є правильним виразом sed. Ви впевнені, що хочете це з sed? Будь-яка мова програмування з хорошими регулярними виразами може замінити вас (пошук підфункції). Це було б простіше, ніж самотужки
розібратися

@Scharron Ну, це робити з сценарієм оболонки, тому я думаю, що sed - це моя найкраща ставка.
Рахул

Відповіді:


483

Ви можете скористатися командою зміни для заміни всього рядка та -iпрапором для внесення змін на місце. Наприклад, за допомогою GNU sed:

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo

4
Зауважте, що вам потрібен пробіл перед c \. Я щойно редагував, щоб додати це.
Marcus Downing

27
@MarcusDowning GNU sed не потребує місця; він працює чудово, як спочатку розміщено. Якщо ваш конкретний sed вимагає місця, то обов'язково зазначайте, який sed є несумісним, і додайте необхідний виклик як коментар. Однак, не змінюйте робочий код у прийнятій відповіді.
Тодд А. Джейкобс

7
Як я можу використовувати змінну замість тексту "Це ..."? Якщо я заміню його на змінну $, вона не друкує її вміст, а ім'я змінної.
Стівен

18
Виникає проблема, c\ коли за нею прямує змінна: …c\$VAR…зворотний косий рятунок долає долар. У цьому випадку я (bash / sed на Ubuntu 15.10) повинен був написати…c\\$VAR…
січня

6
на використанні макінтош: sed -i '' '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo; (коли перший парам порожній, він редагує файл, інакше створює резервну копію)
AndreDurao

152

Щоб .*замінити весь рядок, вам потрібно використовувати wildards ( ) до та після:

sed 's/.*TEXT_TO_BE_REPLACED.*/This line is removed by the admin./'

Спасибі, отримав моє працює: СЄПН 's /.* <вираз> * / <вираз> SE_LABEL = ABC <вираз> / р MYR2.xml> test.txt
Насрі Наджиб

9
Це працює над Mac OS X Yosemite за винятком того, що я використовую прапорці -i та -e таким чином:sed -i -e "s/.*search_string.*/Replacement_line/' file_being_searched.txt
Кент Булл

1
@KentJohnson Я думаю, що у вашій команді невідповідні цитати.
HashHazard

@MBarnett Ви праві, у мене повинні бути дві подвійні лапки.
Кент Булл

2
Просто для отримання повної інформації. Щоб зробити його замість, можна додати -iваріант
Темак

20

Прийнята відповідь не спрацювала для мене з кількох причин:

  • моя версія sed не подобається -iз нульовим розширенням
  • синтаксис c\команди дивний, і я не міг змусити його працювати
  • Я не усвідомлював, що деякі мої проблеми виникають із нерозглянутої косої риски

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

function escape_slashes {
    sed 's/\//\\\//g' 
}

function change_line {
    local OLD_LINE_PATTERN=$1; shift
    local NEW_LINE=$1; shift
    local FILE=$1

    local NEW=$(echo "${NEW_LINE}" | escape_slashes)
    sed -i .bak '/'"${OLD_LINE_PATTERN}"'/s/.*/'"${NEW}"'/' "${FILE}"
    mv "${FILE}.bak" /tmp/
}

Отже, вибірки для вирішення поставленої проблеми:

change_line "TEXT_TO_BE_REPLACED" "This line is removed by the admin." yourFile

18

Відповідь вище:

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo

Добре працює, якщо рядок / рядок заміни не є змінною.

Проблема полягає в тому, що на Redhat 5 \після cвтечі $. Дублік \\теж не працював (принаймні, на Redhat 5).

Через хіт і випробування я виявив, що " \після" cє зайвим, якщо заміна / рядок заміни - лише один рядок. Тому я не використовував \після c, використовував змінну як єдиний рядок заміни, і це було радістю.

Код виглядатиме приблизно так:

sed -i "/TEXT_TO_BE_REPLACED/c $REPLACEMENT_TEXT_STRING" /tmp/foo

Зверніть увагу на використання подвійних лапок замість одинарних лапок.


Ви все ще можете використовувати одиничні цитати на зразок цієї: sed -i '/ TEXT_TO_BE_REPLACED / c' "$ VARIABLE" '' / tmp / foo
Алістер Макінтайр

4

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

Наступні приклади демонструють видалення або зміну тексту за певними номерами рядків:

# replace line 17 with some replacement text and make changes in file (-i switch)
# the "-i" switch indicates that we want to change the file. Leave it out if you'd
#   just like to see the potential changes output to the terminal window.
# "17s" indicates that we're searching line 17
# ".*" indicates that we want to change the text of the entire line
# "REPLACEMENT-TEXT" is the new text to put on that line
# "PATH-TO-FILE" tells us what file to operate on
sed -i '17s/.*/REPLACEMENT-TEXT/' PATH-TO-FILE

# replace specific text on line 3
sed -i '3s/TEXT-TO-REPLACE/REPLACEMENT-TEXT/'

3

для маніпулювання файлами конфігурацій

я придумав це рішення, натхнене відповіддю скенселла

configLine [searchPattern] [replaceLine] [filePath]

це буде:

  • створити файл, якщо його немає
  • замінити всю рядок (усі рядки) , де searchPattern узгоджену
  • додайте substituLine в кінці файлу, якщо шаблон не знайдено

Функція:

function configLine {
  local OLD_LINE_PATTERN=$1; shift
  local NEW_LINE=$1; shift
  local FILE=$1
  local NEW=$(echo "${NEW_LINE}" | sed 's/\//\\\//g')
  touch "${FILE}"
  sed -i '/'"${OLD_LINE_PATTERN}"'/{s/.*/'"${NEW}"'/;h};${x;/./{x;q100};x}' "${FILE}"
  if [[ $? -ne 100 ]] && [[ ${NEW_LINE} != '' ]]
  then
    echo "${NEW_LINE}" >> "${FILE}"
  fi
}

магія статусу шаленого виходу походить від https://stackoverflow.com/a/12145797/1262663


2
bash-4.1$ new_db_host="DB_HOSTNAME=good replaced with 122.334.567.90"
bash-4.1$ 
bash-4.1$ sed -i "/DB_HOST/c $new_db_host" test4sed
vim test4sed
'
'
'
DB_HOSTNAME=good replaced with 122.334.567.90
'

це чудово працює


1

У своєму makefile я використовую це:

@sed -i '/.*Revision:.*/c\'"`svn info -R main.cpp | awk '/^Rev/'`"'' README.md

PS: НЕ забувайте, що -i фактично змінює текст у файлі ... тому якщо шаблон, який ви визначили як "Перегляд", зміниться, ви також зміните шаблон для заміни.

Приклад виводу:

Abc-проект написаний Джоном Доу

Редакція: 1190

Отже, якщо ви встановите шаблон "Ревізія: 1190", це, очевидно, не те саме, що ви їх визначили як "Перегляд:" лише ...


1
cat find_replace | while read pattern replacement ; do
sed -i "/${pattern}/c ${replacement}" file    
done 

Файл find_replace містить 2 стовпці, c1 з відповідним малюнком, c2 із заміною, цикл sed замінює кожен рядок, що поєднує один із шаблонів змінної 1


Ні, це неправильно в кількох аспектах. Запустіть sedодин раз файлом сценарію, що містить усі заміни, які ви хочете виконати. Запуск sed -iодного і того ж файлу неодноразово - жахливий антипатерн.
трійка

0

Це так само, як вище. ..

sed 's/[A-Za-z0-9]*TEXT_TO_BE_REPLACED.[A-Za-z0-9]*/This line is removed by the admin./'

3
Це зміни FOO=TEXT_TO_BE_REPLACEDв FOO=This line ...так не відповідає специфікації.
Єнс

Так .. Наша вимога - замінити весь рядок на "Цей рядок видалено адміністратором." якщо ми знайшли ключ pattren 'TEXT_TO_BE_REPLACED'. Наведена вище команда задовольняє. Виправте мене, якщо моє розуміння неправильне .. @Jens
Annapureddy Hari

@AnnapureddyHari ця відповідь не працює, якщо текст перед або після рядка пошуку має що-небудь у ньому, крім A-Za-z0-9. Він зазнає невдачі, якщо є знак рівності, як вказував Єнс. Частина "FOO =" залишиться; ви не замінили весь рядок. Цей код короткозорий про те, що може бути у файлі. Якщо ви маєте на увазі підстановку, вам слід поставити підстановку, як свідчить відповідь Тор.
msouth

0

Нижче команда працює для мене. Яка робота зі змінними

sed -i "/\<$E\>/c $D" "$B"

Але моя нова вимога - коментувати SKIP (починаючи з #) рядка під час заміни. Оскільки ми замінюємо повний рядок, це також замінить коментовані рядки, і ви отримаєте подвійні властивості. Якщо у когось є рішення на це, будь ласка, дайте мені знати.
Ritesh Borkar

-1

Я дуже часто використовую регулярний вираз для отримання даних з файлів , я використав тільки що замінити буквальну цитату \"з //нічого :-)

cat file.csv | egrep '^\"([0-9]{1,3}\.[0-9]{1,3}\.)' | sed  s/\"//g  | cut -d, -f1 > list.txt
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.