Grep слово и нужно заменить строку выше для этого конкретного тега

#bash #shell #awk #sed #grep

#bash #оболочка #awk #sed #grep

Вопрос:

У меня есть HTML-код, как показано ниже:

 <html>
<head>
<style>
table, th, td {
border:1px solid black;border-collapse:collapse
}
</style>
</head>
<body>
<table style=width:30%>
<tr>
<td>version2</td>
<td>FAIL</td>
</tr>
<tr>
<td>version1</td>
<td>FAIL</td>
</tr>
<tr>
<td>version6</td>
<td>PASS</td>
</tr>
  

Всякий раз, когда я вижу, что ключевое слово НЕ работает в тегах, мне нужно заменить приведенный выше код, как показано ниже. Для ПРОХОЖДЕНИЯ ничего не нужно делать.

 <html>
<head>
<style>
table, th, td {
border:1px solid black;border-collapse:collapse
}
</style>
</head>
<body>
<table style=width:30%>
<tr bgcolor="red">
<td>version2</td>
<td>FAIL</td>
</tr>
<tr bgcolor="red">
<td>version1</td>
<td>FAIL</td>
</tr>
<tr>
<td>version6</td>
<td>PASS</td>
</tr>
  

Используя sed, я могу выполнить поиск слова и заменить его, используя команду ниже:

 sed -i 's/<tr>/<tr bgcolor="red">/g'
  

Но в моем случае сначала мне нужно выполнить поиск по ключевому слову FAIL, затем этот конкретный <tr> тег необходимо заменить.

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

1. Извините, невозможно анализировать XML-файлы с помощью регулярных выражений с помощью sed. Используйте инструменты, поддерживающие xml. Например, xmllint .

2. Не то чтобы это было совершенно невозможно; вы могли бы написать симулятор самолета sed , если бы действительно очень захотели. Но вы этого не делаете.

Ответ №1:

Используя GNU awk, чтобы определить разделитель записей из нескольких символов:

 awk -v RS='<tr>' 'NR > 1 { rs = /FAIL/ ? "<tr bgcolor="red">" : RS } { printf "%s%s", rs, $0 }' file
  

При этом <tr> в качестве разделителя записей используется открывающий тег, который заменяет его, если /FAIL/ соответствует какой-либо части записи.

Мы используем NR > 1 так, чтобы это начиналось только после первой записи, чтобы избежать получения дополнительного <tr> значения в начале вывода. Для первой записи (все, вплоть до первой <tr> во входных данных), rs остается неустановленным, поэтому при печати будет отображаться пустая строка.

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

1. @Fenech, с помощью приведенного выше кода он заменяется на тег ключевого слова FAIL вместе с указанным выше тегом ключевого слова PASS.

2. Я запустил его с вашим образцом ввода, и он только изменил <tr> содержимое FAIL . Возможно, ваш реальный ввод немного отличается?

3. @Rama Я только что понял, что в моем ответе была ошибка, и она добавляла a <tr> в начало вывода. Сейчас я это исправил.

Ответ №2:

 awk 'BEGIN { 
             RS="<tr>|</tr>" 
           } 
$0 ~ /FAIL/ { 
             print "<tr bgcolor="red">"$0"</tr>" 
            } 
$0 ~ /PASS/ { 
             print "<tr>"$0"</tr>" 
            }
!/PASS/ amp;amp; !/FAIL/ { 
             print $0 
            }' html
  

Одна строка:

 awk 'BEGIN { RS="<tr>|</tr>" } $0 ~ /FAIL/ { print "<tr bgcolor="red">"$0"</tr>" } $0 ~ /PASS/ { print "<tr>"$0"</tr>" } !/PASS/ amp;amp; !/FAIL/ { print $0 }' html
  

Используя awk с файлом с именем html, установите разделитель записей на открывающий или закрывающий теги tr, затем выполните поиск в записи ($ 0) на предмет сбоя при печати тегов tr с $ 0 соответственно. Сделайте то же самое для PASS.

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

1. он работает нормально, но не распознает HTML-код, отличный от тегов <tr> </tr>

2. Ну, в вашем примере не было другого html. Возможно, вы могли бы обновить?

3. Я обновил ответ, чтобы учесть любой другой HTML

4. ОК. Попробуйте сейчас.

5. Спасибо, Раман, но я не полностью понял код.. возникает путаница. Но он работает нормально.. Не могли бы вы, пожалуйста, ознакомить меня с кодом. Я действительно ценю ваши усилия, особенно за 0 долларов.

Ответ №3:

В соответствии с вашими примерами, не могли бы вы попробовать следующий.

 tac file | awk '/<td>FAIL</td>/{y=1} y amp;amp; /^<tr>/{print "<tr bgcolor="red">";next} {print}' | tac
  

Я использую решение tac и awk для того же, где tac будет считывать файл в обратном порядке, а awk будет обрабатывать записи в соответствии с заданным условием. В дополнение к этому, передача вывода awk cmd в tac для получения записей в нужном порядке

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

1. с помощью приведенного выше даже для ключевого слова PASS оно также заменяется до тех пор, пока не встретит ключевое слово FAIL.

2. @Rama, я думаю, что этот флаг необходимо отключить, после выполнения условия здесь проблема.

Ответ №4:

Ниже приведено решение, которое буферизует ввод. Он также обрабатывает отступы и пропускает другие элементы HTML.

 # if current line starts a table row, save it in tr
$0 ~ "<tr>" { tr = $0; next }

# if we are inside a table row, append it to tr
$0 !~ "</tr>" amp;amp; tr != "" { tr = tr "n" $0; next }

# if current line ends a table row, insert bgcolor if needed
# and print the previously saved tr variable
$0 ~ "</tr>" {
    if (index(tr, "<td>FAIL</td>") > 0) {
        sub("<tr>", "<tr bgcolor="red">", tr)
    }
    print tr "n" $0
    tr = ""
    next
}

# when current line is not inside a table row just print it
{ print }
  

Если скрипт сохранен в highlight-failing.awk и HTML в versions.html , команда может быть вызвана с помощью

 awk -f highlight-failing.awk versions.html
  

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

1. в приведенном выше коде, где нам нужно передать наш входной файл.