sed — «неизвестная команда» при замене шаблона содержимым файла

#bash #sed #runtime-error

#bash #sed #время выполнения — ошибка

Вопрос:

Я пытаюсь манипулировать некоторыми «шаблонными» текстовыми файлами. Это означает, что файлы содержат некоторые «токены», которые необходимо заменить некоторыми реальными строками — либо жестко закодированными, либо читаемыми из других файлов.

У меня есть следующие 2 строки:

     sed -r -e 's_<!-- cssintern -->_<style type="text/css">n<!-- cssintern -->n</style>n_' -i "$out_dir_aca/books_1by1/independent/$(basename "$aca_frag").html"
    sed -e '^<!-- cssintern -->^' -e '{r '"$src_dir_frags_struct/styles1.css.frag" -e 'd}' -i "$out_dir_aca/books_1by1/independent/$(basename "$aca_frag").html"
 

Первый работает нормально. Проблема в том, что вторая генерирует ошибку «неизвестная команда», и у меня закончились идеи, как это исправить. Вывод отладки следующий (текст ошибки в последней строке):

   for aca_frag in $out_dir_aca/frags_1by1/*
  '[' -f '/home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/2_txt_out/aca/frags_1by1/09.14 - Acatistul inaltarii Sfintei Cruci.frag' ']'
   basename '/home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/2_txt_out/aca/frags_1by1/09.14 - Acatistul inaltarii Sfintei Cruci.frag'
  echo '    09.14 - Acatistul inaltarii Sfintei Cruci.frag'
    09.14 - Acatistul inaltarii Sfintei Cruci.frag
  cat '/home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/1_txt_in/##_frags_struct_##/doctypeXHTML.frag'
   basename '/home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/2_txt_out/aca/frags_1by1/09.14 - Acatistul inaltarii Sfintei Cruci.frag'
  cat '/home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/1_txt_in/##_frags_struct_##/head.frag'
   basename '/home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/2_txt_out/aca/frags_1by1/09.14 - Acatistul inaltarii Sfintei Cruci.frag'
  cat '/home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/1_txt_in/##_frags_struct_##/foot.frag'
   basename '/home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/2_txt_out/aca/frags_1by1/09.14 - Acatistul inaltarii Sfintei Cruci.frag'
   basename '/home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/2_txt_out/aca/frags_1by1/09.14 - Acatistul inaltarii Sfintei Cruci.frag'
  sed -r -e 's_<!-- cssintern -->_<style type="text/css">n<!-- cssintern -->n</style>n_' -i '/home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/2_txt_out/aca/books_1by1/independent/09.14 - Acatistul inaltarii Sfintei Cruci.frag.html'
   basename '/home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/2_txt_out/aca/frags_1by1/09.14 - Acatistul inaltarii Sfintei Cruci.frag'
  sed -re '^<!-- cssintern -->^' -re '{r /home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/1_txt_in/##_frags_struct_##/styles1.css.frag' -re 'd}' -i '/home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/2_txt_out/aca/books_1by1/independent/09.14 - Acatistul inaltarii Sfintei Cruci.frag.html'
sed: -e expression #1, char 1: unknown command: `^'
 

Я использовал для разделителей ^ , _ , / , я использовал «все» способы с простыми и двойными кавычками и все остальное, что я нашел в Интернете. Ничто не меняет того факта, что ошибка остается.

В прошлом я использовал эту строку

 sed.exe -i -e '/%%H/{r ../##_frags_##/out/%%H' -e 'd}' .outout.frag
 

в скрипте Windows cmd и работал нормально. ( %%H ссылается на имя файла при разборе всех файлов в папке с помощью a for ). Я на самом деле переписываю старые скрипты в Linux, как упражнение — надеюсь, для добавления простоты и дополнительных функций.

Я намерен адаптировать следующую sed команду:

 sed -e '/<TEXT1>/{r File1' -e 'd}' -i File2
 

для моих конкретных потребностей.

Примечание: я предоставил точные имена файлов и пути, думая, что они могут дать представление.

Примечание: Я использую Debian 10.7 на виртуальной машине.

Примечание: файл сценария начинается с #!/bin/bash -xv . -xv очевидно, используется только при отладке, в противном случае отсутствует.

Комментарии:

1. Что вы ожидаете от выражения -e '^<!-- cssintern -->^' ? Я не вижу там команды sed.

2. @larsks: Я не уверен, что понимаю ваш вопрос. Я пытаюсь реализовать решение, представленное здесь: unix.stackexchange.com/a/49438/383155 . В итоге я использовал ^ вместо / , но ни один из них все равно не работает. Это <!-- cssintern --> просто строка, «шаблон». Я пробовал использовать просто cssintern , без каких-либо специальных символов, также без положительного результата.

3. -e '^<!-- cssintern -->^' была бы допустимой командой sed. Вам нужно сообщить sed, что вы используете другой разделитель.

4. @KamilCuk: я «оказался» там, когда отказался от попыток найти разделитель, который будет работать. Я начал с / , и это не удалось, поэтому перешел к другим. Возврат без других изменений будет бесполезным (я уже пытался, в результате вашего комментария). » Невозможно проанализировать xml с помощью регулярных выражений «. — это довольно глупо, конечно, это возможно. Я согласен, меня могут не рекомендовать по разным причинам, но это невозможно?! И учитывая, что я хочу заменить только очень конкретную строку другой строкой, я не вижу причин не использовать sed / regexes .

5. @oguzismail: Я пробовал это, но безуспешно. sed -e '^<!-- cssintern -->^' -e '{r /home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/1_txt_in/##_frags_struct_##/styles1.css.frag' -e d -e '}' -i '/home/vici/Dropbox/MyFiles/work/___rug/_!_workarea/2_txt_out/aca/books_1by1/independent/12.17 - Acatistul Sfantului Proroc Daniel.frag.html' sed: -e expression #1, char 21: missing command . Командная строка: sed -e '^<!-- cssintern -->^' -e '{r '"$src_dir_frags_struct/styles1.css.frag" -e 'd' -e '}' -i "$out_dir_aca/books_1by1/independent/$(basename "$aca_frag").html" .

Ответ №1:

Синтаксис такой (комментарий мой)::

 [2addr] {editing command       # No newline between '[2addr]' and '{'!
editing command
...
}
 

Где [2addr] , например /filtering/ , выражения. Опция -e выполняет (выделение мое):

Если указаны какие-либо опции -e или -f, сценарий редактирования команд изначально должен быть пустым. Команды, указанные каждой опцией -e или -f, должны быть добавлены в скрипт в указанном порядке. При каждом добавлении, если предыдущее добавление (если таковое было) было из опции a -e, перед новым добавлением должна быть вставлена <новая строка>. Результирующий скрипт должен иметь те же свойства, что и операнд скрипта, описанный в разделе «ОПЕРАНДЫ».

Когда между [2addr] и есть символ { новой строки, скрипт недействителен:

 $ sed -e '/something/' -e '{' -e '}' /dev/null
sed: -e expression #1, char 11: missing command
$ sed '
/something/
{
}' /dev/null
sed: -e expression #1, char 13: unknown command: `
'
 

Установка { with [2addr] устраняет проблему, поскольку удаляет новую строку:

 $ sed -e '/somethimg/{' -e '}' /dev/null
 

Поэтому поместите его в выражение фильтрации:

 sed
   -e '^<!-- cssintern -->^{'
   #   ^^                  ^^ here '{' is with /expression/
   # or just: -e '/<!-- cssintern -->/{'
   -e 'r blabla/styles1.css.frag'
   -e d
   -e '}' -i 'blabla/12.17 - Acatistul Sfantului Proroc Daniel.frag.html'
 

Должно быть хорошо.

Комментарии:

1. Конечно, по-прежнему нет причин использовать ^ вместо / в первом регулярном выражении.

2. Кроме того, вероятно, объединить два сценария в один.