BSD sed/awk перемещение части строки на строку выше (смена атрибута в HTML файле)

Вопрос или проблема

Моя ситуация проста: у меня есть HTML-файл с несколькими строками, содержащими только <section> блок-тег, каждая строка сопровождается (также с отступом) <h3 id="YYYY">...</h3> тегом заголовка.

Вот так:

    <section>
        <h3 id="2024"><a href="index.fr.html#2024">fr</a> 2024 <a href="index.html#2024">en</a></h3>

При использовании привязанной ссылки для перехода к конкретному году на странице (или его переводу), титул года скрывается за <header>.

Проблема будет решена путем перемещения атрибута id на одну строку выше, от <h3> к тегу <section>,

вот так:

    <section id="2024">
        <h3><a href="index.fr.html#2024">fr</a> 2024 <a href="index.html#2024">en</a></h3>

Есть ли простая однострочная команда, которая позволила бы мне переместить все эти атрибуты id из тега <h3> в тег <section> на одну строку выше? Я не нашел, как сопоставить несколько строк в BSD sed или особенно в awk.

sed 's:<section>\(\s*\)<h3\( id="\[0-9\]{4}"\):<section\2>\1<h3:g' index.html
не изменяет файл. Также не сработает \n\t\t вместо \s или использование двойных обратных слэшей.

Есть ли опция для сопоставления пробельных символов, как я предполагаю, GNU sed будет делать? Только, возможно, вставка/использование новых строк/табуляций прямо в команде, но я хотел бы лучше разобраться и также вынужден, так как работаю удаленно и должен использовать termux на Android… Также я не обладаю достаточными навыками для использования обхода с помощью awk.

Бессмысленный файл с совпадающими и не совпадающими строками, а также пара строк, которые уже имеют правильный формат:

$ cat index.html
<html>
    <section>
        <h2 id="2023"><a href="index.fr.html#2023">fr</a> 2023 <a href="index.html#2023">en</a></h3>

    <section>
        <h3 id="2024"><a href="index.fr.html#2024">fr</a> 2024 <a href="index.html#2024">en</a></h3>

    <section id="2025">
        <h3><a href="index.fr.html#2025">fr</a> 2025 <a href="index.html#2025">en</a></h3>
</html>

Хотя это может быть возможно сделать с помощью sed, мои навыки sed не на высоте.

Хотя автор вопроса заявил – Я не обладаю достаточными навыками для использования обхода с помощью awk – вопрос был помечен тегом awk, так что я попробую решить задачу с помощью awk

awk -F'[<>]' '                                                  # разделить по двойным разделителям "<" и ">"
$2 == "section" { line1 = $0                                    # если 2-е поле "section", сохранить текущую строку
                  if (getline && $2 ~ /^h3 id=/) {              # прочитать следующую строку, и если 2-е поле начинается с "h3 id=", тогда ...
                     match($2,/id=.*$/)                         # найти строку "id=..."
                     id = substr($2,RSTART,RLENGTH)             # сохранить указанную строку
                     sub(/<section>/,"<section " id ">",line1)  # обновить переменную "line1"
                     sub("<h3 " id ">","<h3>")                  # обновить текущую строку
                  }
                  print line1                                   # напечатать "line1"
                }
1                                                               # напечатать текущую строку
' index.html

Это генерирует:

<html>
    <section>
        <h2 id="2023"><a href="index.fr.html#2023">fr</a> 2023 <a href="index.html#2023">en</a></h3>

    <section id="2024">
        <h3><a href="index.fr.html#2024">fr</a> 2024 <a href="index.html#2024">en</a></h3>

    <section id="2025">
        <h3><a href="index.fr.html#2025">fr</a> 2025 <a href="index.html#2025">en</a></h3>
</html>

Ответ или решение

Ваш запрос о том, как переместить атрибут id из тега <h3> в тег <section> в HTML-файле, требует корректного использования инструментов обработки текста, таких как sed и awk. Давайте разберем вашу задачу более подробно и предложим решение, подходящее для использования в среде BSD.

Проблема

У вас есть HTML-файл, в котором теги <h3> содержат атрибут id, и вы хотите переместить этот атрибут в тег <section>, расположенный выше. Это действие поможет исправить проблему с наложением заголовков на (или загораживанием) других элементов интерфейса на странице.

Пример строки до изменения:

<section>
    <h3 id="2024"><a href="index.fr.html#2024">fr</a> 2024 <a href="index.html#2024">en</a></h3>
</section>

Необходимый результат:

<section id="2024">
    <h3><a href="index.fr.html#2024">fr</a> 2024 <a href="index.html#2024">en</a></h3>
</section>

Решение с использованием awk

Хотя sed может использоваться для проблемы, awk часто предоставляет больший контроль при обработке многострочных шаблонов, особенно когда необходимо взаимодействовать с данными, расположенными на нескольких строках. Вот работающий пример скрипта на awk, который выполнит вашу задачу.

Команда awk

awk -F'[<>]' '
$2 == "section" { 
    line1 = $0                                    # Запоминает текущую строку для тега <section>
    if (getline && $2 ~ /^h3 id=/) {             # Проверяет, если следующая строка - <h3 id="...">
        match($2, /id="[^"]+"/)                  # Находит id атрибут
        id = substr($2, RSTART, RLENGTH)         # Сохраняет id
        sub(/<section>/, "<section " id ">", line1)  # Добавляет id в тег <section>
        sub(/ id="[^"]+"/, "", $0)                # Удаляет id из тега <h3>
    }
    print line1                                  # Выводит модифицированный <section>
    print $0                                     # Выводит модифицированный <h3>
    next                                         # Переходит к следующей строке
}
1                                               # Обрабатывает остальные строки без изменений
' index.html

Объяснение:

  1. -F'[<>]': Устанавливает разделитель на < и >, что позволяет легко извлекать содержимое тега.
  2. $2 == "section": Проверяет, что текущая строка является тегом <section>, затем сохраняет её в переменной line1.
  3. if (getline && $2 ~ /^h3 id=/): Использует getline для перехода к следующей строке и проверяет, является ли она тегом <h3> с атрибутом id.
  4. match($2, /id="[^"]+"/): Использует функцию match для извлечения значения id.
  5. sub(/<section>/, "<section " id ">", line1): Модифицирует строку line1, добавляя найденный id.
  6. sub(/ id="[^"]+"/, "", $0): Удаляет id из текущей строки <h3>.
  7. print line1 и print $0: Печатает обновленные строки.
  8. 1: Условие, которое всегда истинно, заставляет awk напечатать остальные строки без изменений.

Заключение

С помощью данной команды awk вы сможете переместить атрибут id из тега <h3> в тег <section>, что устранит проблему с наложением заголовка. Убедитесь, что ваш HTML-файл имеет правильный формат перед запуском команды, чтобы избежать неожиданных результатов. Если у вас возникнут дополнительные вопросы или потребуется поддержка, пожалуйста, не стесняйтесь обращаться за помощью.

Оцените материал
Добавить комментарий

Капча загружается...