Почему Сед делать больше, что я спросил?

Когда я применил sed -i -e "s/..\///" -e "s/type_properties\///" testfile к следующему файлу:

 #include "../../../../include/concepts/type_properties/operations/has_or_op_v.hpp" int main() { // Test has_not_op_v. } 

Это выводит это:

 #include "../../../include/concepts/operations/has_or_op_v.hpp" int main() { / Test has_not_op_v. } 

Я просто хотел, чтобы sed удалил один ../ и удалил type_properties/ , но это также испортило мою аннотацию.

Персонаж . это метасимвол Это означает, что оно имеет особое значение. . означает «соответствовать любой отдельной букве или символу». Вы хотите соответствовать только буквальному . персонажи.

Если вы измените . к \. , вы получите правильный вывод.

Пример:

 sed -i -e "s/..\///" -e "s/type_properties\///" testfile 

будет выглядеть так:

 sed -i -e "s/\.\.\///" -e "s/type_properties\///" testfile 

Прежде всего, не используйте sed -i при тестировании. Запустите сначала без -i и проверьте результат. Если вы знаете, что все выглядит правильно, добавьте -i чтобы зафиксировать изменение в файле на месте.

Кажется, причина в sed больше, чем в том, что его просят, в том, что комментарий в функции main() соответствует первому из двух ваших выражений, ..\/ (два символа и косая черта).

Если вы знаете, что хотите применить только изменения к строкам, начинающимся с #include , вы можете использовать

 sed -e '/^#include/{s%\.\./%%; s%type_properties/%%;}' file.c 

Здесь две замены выполняются только в строках, начинающихся со строки #include . Я также правильно экранировал две точки в первом выражении, чтобы они соответствовали точкам, а не «любому символу». Поскольку текст, который мы сопоставляем, содержит косую черту, я также выбрал использование альтернативного разделителя % в командах s .