Bash: как сделать определенные строки, но исключить определенные линии между ними? - PullRequest
0 голосов
/ 30 мая 2019

У меня есть файл, который выглядит так:

a: 0
a: 0
a: 0
a: 1
b: 1
c: 1
d: 1
e: 1
f: 1
a: 2
b: 2
c: 2
d: 2
e: 2
f: 2
a: 3
b: 3
c: 3
d: 3
e: 3
f: 3
c: 4
c: 4
c: 4

Я хочу захватить и вывести все строки a и c вида <a line><anything other than an a or c line><c line>, чтобы результат выглядел следующим образом:

a: 1
c: 1

a: 2
c: 2

a: 3
c: 3

Обратите внимание, что ни строки a: 0 в начале, ни строки c: 4 в конце не захватываются, поскольку они не следуют шаблону, который я упоминал. Также обратите внимание, что строки b между строками a и c удалены.

Я пытался сделать это с осторожностью, используя pcregrep Bash, но пока не нашел решения. Есть идеи?

Спасибо!

1 Ответ

4 голосов
/ 30 мая 2019

Использование awk

Попытка:

$ awk -F: '$1=="a"{aline=$0} $1=="c"{if(aline)print aline ORS $0 ORS; aline=""}' file
a: 1
c: 1

a: 2
c: 2

a: 3
c: 3

Как это работает

По умолчанию awk читает по одной строке за раз.

  • -F:

    Это говорит awk использовать : в качестве разделителя полей.

  • $1=="a"{aline=$0}

    Каждый раз, когда наблюдается строка a, сохраняйте строку в переменной aline.

  • $1=="c"{if(aline)print aline ORS $0 ORS; aline=""}

    Каждый раз, когда наблюдается линия c, проверьте, есть ли у нас непустая aline. Если это так, выведите aline и текущую строку, разделенные символами новой строки. Также установите aline обратно в пустую строку.

Многострочная версия

Для тех, кто предпочитает, чтобы их команды распределялись по нескольким строкам:

awk -F: '
    $1=="a"{
        aline=$0
    }

   $1=="c"{
        if(aline)
            print aline ORS $0 ORS
        aline=""
    }' file

Использование sed

$ sed -n '/^a/h; /^c/{x;/^a/{p;x;s/$/\n/;p};h}' file
a: 1
c: 1

a: 2
c: 2

a: 3
c: 3

Как это работает

  • -n

    Это говорит sed не печатать ничего, если мы явно не попросим об этом.

  • /^a/h

    Каждый раз, когда у нас появляется строка, начинающаяся с a, мы сохраняем ее в поле удержания.

  • /^c/{ x; /^a/{ p; x; s/$/\n/; p}; h}

    Каждый раз, когда у нас есть строка, начинающаяся с c, мы:

    • Меняем (x) пространство шаблона на пространство удержания.

    • Если новое пространство образца начинается с a, то мы печатаем его (p) и снова меняем местами (x), добавляем новую строку в конец нового пространства образца (s/$/\n/) и распечатайте (p) его.

    • Наконец, мы сохраняем текущее пространство шаблона (которое начинается с c) в поле удержания.

...