![Sed заменяет только четные строки файла, если команды замены записаны в файле](https://rvso.com/image/1416716/Sed%20%D0%B7%D0%B0%D0%BC%D0%B5%D0%BD%D1%8F%D0%B5%D1%82%20%D1%82%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE%20%D1%87%D0%B5%D1%82%D0%BD%D1%8B%D0%B5%20%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8%20%D1%84%D0%B0%D0%B9%D0%BB%D0%B0%2C%20%D0%B5%D1%81%D0%BB%D0%B8%20%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B%20%D0%B7%D0%B0%D0%BC%D0%B5%D0%BD%D1%8B%20%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D1%8B%20%D0%B2%20%D1%84%D0%B0%D0%B9%D0%BB%D0%B5.png)
У меня есть все команды замены в файле (например, 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_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
file в группу команд. В моем поверхностном тестировании это, похоже, решает проблемы, которые я поднял в других решениях. Я не буду шокирован, если у него возникнут проблемы с очень длинными replace.sed
или с очень сложными командами.