У меня есть блок текста, который мне нужно удалить, однако, только если он содержит определенный текст внутри блока:

...
<script language="JavaScript">
    var somethingA = 0;
    var somethingB = 0;
    var somethingC = 0;
    // do some stuff
</script>

<script language="JavaScript">
    var somethingA = 0;
    var somethingC = 0;
    var somethingD = 0;
    // do some stuff
</script>
....

Я хочу удалить только блок <script> котором есть var somethingB B. Может быть любое количество блоков <script> в файле в любой позиции.

Я надеялся использовать sed, делая что-то вроде:

sed 's/<script/,/<\/script>/ D'

Тем не менее, я не могу понять, как удалить только блок с var somethingB в нем.

PS: я также мог бы использовать perl или awk. Я бы предпочел использовать sed для согласованности, но если это проще в perl и / или awk, я бы довольно быстро переключал передачи. Спасибо!

3 ответа3

1

Если частичное решение в vim приемлемо:

:%s/<script [^<]*\(\n[^<]*\)*somethingB.*\(\n[^<]*\)*<\/script>//g

но он не будет работать, если внутри <script> есть другие теги, потому что при использовании [^<] шаблон может не содержать < .

0

Это должно быть выполнимо в sed напрямую. Как я не sed мастер, мне нужно два прохода.

  1. В первом запуске мы подготавливаем файл, чтобы убедиться, что блоки <script>...</script> заключены в пустые строки:

    sed -e '/<script/i\ ' -e '/script>/a\ ' code.js
    

    Это не ракетостроение: i вставляю строку перед строкой, соответствующей шаблону, a соответственно добавляю строку после строки, соответствующей шаблону. В обоих случаях строка состоит только из одного пробела.

    Это необходимо для того, чтобы sed обнаруживал каждый блок отдельно, т. Е. Не жадно на втором этапе).

  2. Второй прогон убивает блоки с var somethingB в нем:

    sed '/<script/,/script>/{H;d;};x;/var somethingB/d'
    
    • /<script/,/script>/{H;d;} перемещает блок в пространство хранения sed (H добавляет в пространство хранения, d удаляет из пространства шаблона)
    • x заменяет пространство удержания на пространство шаблона
    • если шаблон /var somethingB/ соответствует удалить (d) пространство шаблона, которое содержит полный блок <script> .
    • наконец, sed неявно печатает шаблон пространства.

      Моя ссылка здесь была Unix Sed Tutorial .

  3. Итак, в одной командной строке с хорошей трубкой:

    sed -e '/<script/i\ ' -e '/script>/a\ ' code.js | sed '/<script/,/script>/{H;d;};x;/var somethingB/d'
    

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

    sed '/^ $/d'
    
0

У меня нет простого решения. На самом деле он использует awk для кодирования необходимого алгоритма на C-подобном языке awk. Предполагая, что текст для фильтрации находится в файле с именем 'filename':

awk 'BEGIN { curr=0 } \
     /<script .*>/ { in_block=1; del_block=0 } \
     /<\/script>/ { in_block=0; blockend=1 } \
     /var[[:space:]]+somethingB/ { if (in_block==1) \
                                     { del_block=1 } } \
    { if (in_block==0) \
        { if (blockend==0) \
            # Neither in a block nor block end reached.
            # Just print the line
            { print } \
          else \
            { # End of a block reached. Do block end handling
              # just this one time. Block end flag off
              blockend=0
              if (del_block==1) \
                { # delete the block. Just throw away the lines
                  # in the lines array
                  curr=0 } \
              else \
                { # End of block and no delete. Print it out
                  for (i=0; i<curr; i++) \
                    { print line[i] }
                    print   # Print the </script> line
                      # use line-array for the next block
                      curr=0 \
                } \
            } \
        } \
      else \
        { # In a block. Save the current line for later
          line[curr]=$0
          curr++ } \
    }' filename

Шаблон для </script> (конечный маркер блока) немного прост. Ожидается, что он написан именно так без пробелов. Если он может содержать пробелы, вы можете написать это так:

/<[[:space:]]*\/script[[:space:]]*>/ 

Шаблон для var somethingB - это var - один или несколько пробелов - somethingB , что, вероятно, и является тем, что вы ищете. Если вы хотите, чтобы он фиксировался ровно на один пробел между var и somethingB тоB, то это проще: /var somethingB/

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .