3

У меня есть все команды замены в файле (скажем, replace.sed), и я использую его с флагом -f sed (sed -f replace.sed InputFile). Но теперь я столкнулся с условием, когда мне нужно применять эти правила замены только к четным строкам заданного входного файла (т.е. только к строкам № 2,4,6 и т.д.).Я не могу поместить какие-либо операторы условия в файл replace.sed, так как он используется и другими сценариями.

3 ответа3

1
sed -f <(sed -e 's/.*/2~2{&;}/' replace.sed) InputFile
1

Используйте подстановку процесса, чтобы адаптировать команды sed в вашем файле на лету:

$ cat replace.sed
s#foo#bar#

,

$ printf "foo\nfoo\nfoo\nfoo\n" | sed -f replace.sed
bar
bar
bar
bar

,

$ printf "foo\nfoo\nfoo\nfoo\n" | sed -f <(sed 's#^#2~2#g' replace.sed)
foo
bar
foo
bar
1

Что другие ответы говорят вам, пытаясь сказать вам, это использовать форму sed адреса first~step :

Адреса

    ... Поддерживаются следующие типы адресов: ...

    первый шаг
      Соответствует каждой строке шага , начиная с первой строки.  Например, « sed -n 1~2p » напечатает все нечетные строки во входном потоке, а адрес « 2~5 » будет соответствовать каждой пятой строке, начиная со второй.  первым может быть ноль; в этом случае sed работает так, как если бы он был равен шагу.  (Это расширение.)

Очевидное решение состоит в том, чтобы каждой команде в replace.sed предшествовать 2~2 (или 0~2 , если она работает в вашей версии sed), чтобы команды работали на любой другой строке, начиная со второй (т.е. все четные строки во входном потоке, как вы и просили).  Но вы говорите, что не можете изменить replace.sed .  Что ж, следующим шагом (как определено, но не объяснено другими ответами) является создание временного временного файла с возможностью подстановки процессов оболочки, где <(command_list) действует как файл, который является выводом command_list .  Если, как показывает ваш вопрос, replace.sed - это просто последовательность простых команд замены, тогда

sed -f <(sed 's/^/2~2/g' replace.sed)

должно сработать.

Но это имеет недостатки:

  • Если у вас есть несколько команд на строку, то вышеприведенное повлияет только на первую команду в каждой строке.
  • Если у вас есть команды с числовыми адресами (например, 42s/Zaphod/Beeblebrox/), они будут преобразованы, например, в 2~242… , с очевидным последствием.
  • И если у вас есть команды с нечисловыми адресами (например, /windows/s/command/cmd/), вышеприведенный код сразу потерпит неудачу.

Если какой-либо из этих случаев применим, вы должны использовать

sed -f <(sed -e 's/.*/2~2{&;}/' replace.sed)

вариант размещения всех команд sed в каждой строке в группе команд.

Но даже это не удастся, если в replace.sed есть многострочные команды.

Опираясь на вышеизложенные идеи, я придумал

sed -f <(echo '0~2{'; cat replace.sed; echo '}')

который помещает весь файл replace.sed в группу команд.  В моем поверхностном тестировании это, кажется, решает проблемы, которые я поднял с другими решениями.  Я не был бы шокирован, если бы у него была проблема с очень длинным replace.sed или с очень сложными командами.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .