У меня есть все команды замены в файле (скажем, replace.sed), и я использую его с флагом -f sed (sed -f replace.sed InputFile). Но теперь я столкнулся с условием, когда мне нужно применять эти правила замены только к четным строкам заданного входного файла (т.е. только к строкам № 2,4,6 и т.д.).Я не могу поместить какие-либо операторы условия в файл replace.sed, так как он используется и другими сценариями.
3 ответа
sed -f <(sed -e 's/.*/2~2{&;}/' replace.sed) InputFile
Используйте подстановку процесса, чтобы адаптировать команды 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
Что другие ответы говорят вам, пытаясь сказать вам, это использовать форму 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
или с очень сложными командами.