Удалить строку, содержащую первое вхождение «pattern1» после последнего появления «pattern2»?

http://ubuntuforums.org/showthread.php?t=2316240

Ответ здесь. Проблема в том, что каким-то образом определяется общий тачпад, хотя на самом деле используется другой тачпад. Все команды, которые я пробовал, шли к общему тачпаду, которого на самом деле не существует, поэтому ничего не сработало.

Попробовал исправление, и теперь все в порядке.

3
09.08.2017, 23:21
6 ответов

Мы можем выполнить проверку, используя sed, хотя приведенный ниже код написан для GNU sed, где мы сохраняем последний полный диапазон /pat2/../pat1/в пространстве хранения. И затем мы поддерживаем оболочку расширяющейся границы, начиная с линии рядом с последней строкой диапазона, сохраненного в удержании, и продвигаясь к eof.

sed -e '
   /pattern2/,/pattern1/!b
   H;/pattern2/h;/pattern1/!{$!d;g;q;}
   ${g;bc;}
   N;s/.*\n//
   :a
      $bd;N
   /pattern2/!ba
   :b
      $bd;N
   /pattern2.*\n.*pattern1/!bb
   x;$!{n;/pattern2/bb;ba;}
   G
   :c;s/\(.*\)\n.*/\1/;q
   :d;x;s/\(.*\)\n.*/\1/;G
' input,txt

В этом методе мы помещаем весь файл в пространство шаблонов, затем, используя мощь регулярных выражений, находим и определяем последнюю строку /pattern1/ в диапазоне и удаляем ее.

sed -Ee '
   $!{N;H;s/.*//;x;D;}
   /pattern2/!q;/pattern1/!q;/pattern2.*\n.*pattern1/!q
   h;s/((.*\n)?[^\n]*pattern2[^\n]*)\n(.*pattern1.*)/\3/
   s/^//;tdummy
   :dummy
   s/\n[^\n]*pattern1[^\n]*\n/\n/;ta
   s/^[^\n]*pattern1[^\n]*\n//;ta
   s/\n[^\n]*pattern1[^\n]*$//;ta
   s/^[^\n]*pattern1[^\n]*$//
   :a;x;s/((.*\n)?[^\n]*pattern2[^\n]*)\n.*pattern1.*/\1/;G
' input.file
0
27.01.2020, 21:15

Чтобы найти номер строки этой строки:

lineno=$( nl file | tac | awk '/pattern1/ {last = $1} /pattern2/ {print last; exit}' )

Использование nlдля добавления номеров строк в файл,
tacчтобы поменять местами линии,
и awkдля печати номера строки для последнего "шаблона1" перед и первого "шаблона2".

А затем удалить эту строку:

sed -i "${lineno}d" file
0
27.01.2020, 21:15

У меня нет компьютера для тестирования, но это должно работать с gnused:

sed 'H;1h;$!d;g;s/.*pattern1/@@@/;s/\n[^\n]*pattern2[^\n]*//;H;g;s/\(.*pattern1\).*@@@/\1/'

Вместо @@@используйте любую последовательность символов, о которой известно, что она не является частью файла.

0
27.01.2020, 21:15

Это exодин -вкладыш.(exявляется предшественником и скриптовой формой vi.)

printf '%s\n' '$?pattern2?/pattern1/d' x | ex file.txt

Сохранение xи выход. Измените его на %p, если вы хотите просто распечатать измененный файл, но не сохранить изменения (хорошо для тестирования ).

$означает последнюю строку файла; ?pattern2?— адрес, означающий первый результат поиска pattern2в обратном направлении, начиная с текущей позиции; /pattern1/— адрес прямого -поиска, а d— команда удаления строки.

Используйте ex, когда вам нужна прямая и обратная адресация.


То же самое можно сделать интерактивно в viили Vim:

vim file.txt

Затем введите

:$?pattern2?/pattern1/d

и нажмите Enter.

Затем сохраните и выйдите, нажав :xEnter.

5
27.01.2020, 21:15

Сэд:

n=$(sed -ne '/pattern2/,/pattern1/{/pattern1/=;}' yourfile | tail -n 1)
sed -i'' -e "${n}d" yourfile

Сед :за 1 -проход

# invoke GNU sed with extended RE(-E), slurp mode(-z), in-place editing(-i) options
sed -i -Eze '
   h;s/(.*pattern2[^\n]*)\n.*/\1/p;   # traverse till the last pat2 line and print it
   g;s/.*pattern2[^\n]*(\n.*)/\1/;    # remove till the last pat2 line
   s/\n[^\n]*pattern1[^\n]*//;        # now look for the 1st occurrence of pat1
   ;                                  # clip that line, & print what remains
' inp

Рабочий:

  • Определите номер строки /pattern1/, но он должен лежать только в правильном диапазоне, т. е. /pattern2/,/pattern1/для того, чтобы он учитывался.
  • Возьмите последнее из этих чисел.
  • На втором проходе укажите номер строки, определенный выше, и удалите эту строку.

Перл:

     |----A---|   |----B----|--------C--------|D|----------E---------|-F-|
perl -0777pi -e 's/.*pattern2(?:(?!pattern1).)*\K(?-s:\n.*pattern1.*$)//ms' yourfile
  • A:Вызов Perlв режиме slurp(-0777)+ line-by-lineчтение -в +autoprint(-p)включено, in-placeредактирование(-i)
  • B+C:Перейдите к последнему вхождению шаблона2, затем замедлите движение и двигайтесь устойчиво, очищая не шаблон1
  • D:Когда вы доберетесь сюда, это будет последний пит-стоп, где шаблон 1 не был замечен после последнего шаблона 2, отметьте его \K. это означает, что это не появится в потребляемой части ввода, а только в согласованной части.
  • E:Этим мы отключаем модификатор соответствия шаблона /scloistered, что означает, что в этой части совпадения .больше не соответствует новой строке, что означает, что мы не можем переходить дальше строк. Мы просто сопоставляем всю единственную строку с шаблоном1 и удаляем это. То, что остается в пространстве шаблона, печатается автоматически.
  • -F:Мы вызываем s///с модификаторами /sи /m. Мы выборочно отключим модификатор /sвнутри регулярного выражения, чтобы адаптировать его к нашим потребностям.
0
27.01.2020, 21:15

Если вы хотите сделать только один проход в файле и свести к минимуму количество строк, хранящихся в памяти, вы можете использовать awkс подходом конечного автомата.Это не самые короткие решения, но их легко придумать и читать/обслуживать. Вы можете заменить имена состояний числами, чтобы сделать его (возможно )более эффективным.

PATTERN1=pattern1 PATTERN2=pattern2 awk '
  BEGIN {
    p1 = ENVIRON["PATTERN1"]
    p2 = ENVIRON["PATTERN2"]
    state = "init"
  }
  state == "init" {
    if ($0 ~ p2) state = "p2_found"
    print
    next
  }
  state == "p2_found" {
    if ($0 ~ p1) {
      state = "p1_found"
      p1_line = $0
      printf "%s", hold
      hold = ""
    } else if ($0 ~ p2) {
      # we can print the text held since the last p2
      printf "%s", hold
      hold = $0 RS
    } else hold = hold $0 RS
    next
  }
  state == "p1_found" {
    if ($0 ~ p2) {
      state = "p2_found"
      # the line that matched p1 is not discarded
      printf "%s\n%s", p1_line, hold;
      hold = ""
    }
    hold = hold $0 RS
  }
  END {
    # here we are not printing p1_line which is how it is discarded
    printf "%s", hold
  }'

(Я предполагаю, что нет строк, соответствующих как pattern1, так иpattern2).

0
27.01.2020, 21:15

Теги

Похожие вопросы