Sed заменяет только четные строки файла, если команды замены записаны в файле

Sed заменяет только четные строки файла, если команды замены записаны в файле

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

решение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

решение2

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

решение3

Другие ответы пытаются вам подсказать, что нужно использовать форму sedадреса :first~step

Адреса

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

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

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

Связанный контент