sed применяет два условия поиска к одной строке, а затем заменяет

Я хотел бы сделать следующую замену

sed 's/$/)/' python2.py

с условием, что строка содержит print(, но не может содержать print(""".

Строка, которой должно не соответствовать, будет

print("""Some multi line text etc... 

Хотя такие строки должны совпадать

print("Some single line text"

Теперь легко сопоставить одно или исключить другое, но мне не удается объединить оба условия в одну команду. Например

sed -ne '/print(/s/$/)/p' python2.py

Соответствует всем строкам с print(, а также тем, которые я хотел бы опустить с print(""". С другой стороны, я могу пропустить все строки с print(""" с

sed -ne /print("""/! s/$/)/p python2.py

Но это включает в себя все остальные строки, даже без print(. Есть ли способ объединить оба условия, чтобы замена применялась только тогда, когда оба условия верны для строки?

В качестве примечания:

Я знаю, что я могу выполнить два запуска sed, где я сначала делаю замены для всех строк print(, а затем выполняю второй запуск sed, где я удаляю недавно замененные ) только в строках print(""". Я хотел бы знать, можно ли сделать это за один раз, так что это не ответ, который я ищу.


person Hans Wurst    schedule 18.01.2021    source источник
comment
Что делать, если строка уже print("Some single line text")   -  person anubhava    schedule 18.01.2021


Ответы (3)


С GNU sed вы можете использовать

sed '/print("""/!{/print("/s/$/)/}' file > newfile

См. демонстрацию в Интернете.

Подробности:

  • /print("""/! - если найдено print(""", пропустить строку
  • {/print("/s/$/)/} - иначе, если строка содержит print(", заменить конец строки на ).
person Wiktor Stribiżew    schedule 18.01.2021
comment
Здесь также нет ничего сложного в стандартном sed. Некоторые sed диалекты будут настаивать на том, чтобы терминаторы операторов стояли до или после фигурных скобок. Вы можете избежать этого, изменив ! на b, и тогда вам не нужны кудри. - person tripleee; 18.01.2021
comment
Работает по назначению. Синтаксис фигурных скобок был тем, чего мне не хватало. - person Hans Wurst; 18.01.2021
comment
Ага, sed '/print("""/b;/print("/s/$/)/' тоже подойдет. - person Wiktor Stribiżew; 18.01.2021

Вы можете использовать этот sed, чтобы игнорировать строки, которые уже имеют закрывающий ):

cat file
print("""Some multi line text etc...
print("Some single line text"
print("Some single ""line text"
print("Some single line text")

sed '/print("""/!s/print(".*[^)]$/&)/' file
print("""Some multi line text etc...
print("Some single line text")
print("Some single ""line text")
print("Some single line text")

Образец print(".*[^)]$ соответствует строке с тестом из print(" с символом, отличным от ), в конце. &) помещает ) в конец совпадающего шаблона.

person anubhava    schedule 18.01.2021

Это все, что ты пытаешься сделать?

$ cat file
print("""Some multi line text etc...
print("Some single line text"

$ sed 's/print("[^"].*/&)/' file
print("""Some multi line text etc...
print("Some single line text")

Если нет, отредактируйте свой вопрос, чтобы показать более репрезентативный образец ввода/вывода, включающий случаи, для которых это не работает.

person Ed Morton    schedule 18.01.2021