Замените всю строку, содержащую строку, используя 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 \. Я только что отредактировал, чтобы добавить это.
Маркус Даунинг
27
@MarcusDowning GNU sed не требует места; это работает просто отлично, как первоначально отправлено. Если вашему конкретному sed требуется место, то непременно отметьте, какой sed несовместим, и добавьте необходимый вызов в качестве комментария. Однако, пожалуйста, не меняйте рабочий код в принятом ответе.
Тодд А. Джейкобс
7
Как я могу использовать переменную вместо текста "This ..."? Если я заменю его на переменную $, он не печатает содержимое, а имя переменной.
Стивен
18
Существует проблема с тем, c\ когда непосредственно следует переменная: …c\$VAR…обратная косая черта будет избегать доллара. В этом случае мне (bash / sed на Ubuntu 15.10) пришлось написать…c\\$VAR…
января
6
на Mac использовать 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./'
Тор
источник
Спасибо, заставил мою работать: sed 's /.* <выражение>. * / <Выражение> SE_LABEL = ABC <выражение> / g' MYR2.xml> test.txt
Насри Наджиб,
9
Это работает на Mac OS X Yosemite, за исключением того, что я использую флаги -i и -e следующим образом:sed -i -e "s/.*search_string.*/Replacement_line/' file_being_searched.txt
Kent Bull
1
@KentJohnson Я думаю, что вы не соответствовали кавычкам в вашей команде.
HashHazard
@MBarnett вы правы, у меня там две двойные кавычки.
Кент Бык
2
Просто для полной информации. Чтобы сделать это на месте можно добавить -iопцию
Temak
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
skensell
источник
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

Обратите внимание на использование двойных кавычек вместо одинарных.

user4256255
источник
вы все еще можете использовать одинарные кавычки, например: 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/'
b_laoshi
источник
3

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

я придумал это решение, вдохновленное ответом skensell

configLine [searchPattern] [replaceLine] [filePath]

Так и будет:

  • создать файл, если не существует
  • заменить всю строку (все строки), где searchPattern соответствует
  • добавить replaceLine в конец файла, если шаблон не был найден

Функция:

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
'

работает нормально

NKL
источник
1

В моем make-файле я использую это:

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

PS: НЕ забывайте, что -i на самом деле изменяет текст в файле ... поэтому, если шаблон, который вы определили как «Редакция», изменится, вы также измените шаблон для замены.

Пример вывода:

Abc-Project, написанный Джоном Доу

Редакция: 1190

Таким образом, если вы установите шаблон «Revision: 1190», он, очевидно, будет отличаться от того, что вы определили как «Revision:» только ...

Мартин Пфеффер
источник
1
cat find_replace | while read pattern replacement ; do
sed -i "/${pattern}/c ${replacement}" file    
done 

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

sjordi
источник
Нет, это неправильно по нескольким причинам. Запустите sedодин раз с файлом сценария, содержащим все замены, которые вы хотите выполнить. Запуск sed -iна тот же файл несколько раз это ужасны антипаттерны.
tripleee
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 ...так, не соответствует спецификации.
Дженс
Да. Наше требование - заменить всю строку на «Эта строка удалена администратором». если мы нашли ключ паттерна 'TEXT_TO_BE_REPLACED'. Вышеуказанная команда удовлетворяет. Поправьте меня, если мое понимание неверно .. @Jens
Annapureddy Hari
@AnnapureddyHari этот ответ не работает, если в тексте до или после строки поиска есть что-то, кроме A-Za-z0-9. Он потерпел неудачу, если есть знак равенства, как указал Дженс. Часть "FOO =" останется; Вы не заменили всю линию. Этот код недальновиден относительно того, что может быть в файле. Если вы имеете в виду подстановочный знак, вы должны поставить подстановочный знак, как показывает ответ Тора.
MST
0

Ниже команда работает для меня. Который работает с переменными

sed -i "/\<$E\>/c $D" "$B"
Ритеш Боркар
источник
Но мое новое требование - пропустить строку с комментариями (начинается с #) при замене. Поскольку мы заменяем полную строку, это также заменит закомментированные строки, и вы получите дублирующие свойства. Если у кого-то есть решение для этого, пожалуйста, дайте мне знать.
Ритеш
-1

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

cat file.csv | egrep '^\"([0-9]{1,3}\.[0-9]{1,3}\.)' | sed  s/\"//g  | cut -d, -f1 > list.txt
Stam
источник