Как grep текст после двух специальных символов?

В файле изображения может быть метаинформация, которая дает подсказки относительно ориентации изображения.

Средство просмотра изображений Ubuntu будет автоматически вращать их автоматически в зависимости от этих метаданных. Windows Photo Viewer традиционно игнорирует эту информацию.

Это может привести к неожиданным результатам. Одна программа может подчиняться ориентации и поворачиваться для просмотра, а другие - нет.

Существует атрибут ориентации Exif, который может иметь 1 из 8 значений. Могут быть другие схемы / представления метаданных для ориентации изображения. Камеры могут вставлять эту информацию во время съемки.

Чтобы прочитать эти метаданные, я нашел полезную информацию Imagemagick. Доступны другие метаданные. Вы можете отображать эти внедренные атрибуты из вашей программы просмотра фото / изображений (искать свойства изображения).

Для просмотра с помощью Imagemagick:

$ sudo apt-get install imagemagick
$ identify -verbose /path/to/image.file
4
задан 12 May 2017 в 14:11

10 ответов

Наименьшая модификация вашей текущей команды заключалась бы в замене вашего упоминания на буквенный символ | в вашем регулярном выражении ссылкой на класс символов, содержащий как |, так и >, [|>], которые будет соответствовать любому из них:

grep -o ' [|>].*$'| cut -c5-

Другие исследовали реализации awk, sed и perl, но ваша реализация grep также может быть улучшена.

Например, вы можете избавиться от команды cut следующими способами:

с помощью флага Perl \K: grep -Po '[>|]\s*\K.* с помощью внешнего вида PCRE: grep -Po '(?<=[|>]\s).*' обратите внимание, что это будет работать только с фиксированным количеством пробелов между разделителем и целевым словом, так как двигатели PCRE не требуются для реализации переменной ширины lookbehind и обычно этого не делают.
0
ответ дан 18 July 2018 в 13:26

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

awk -F'[>|]' '{print$2}' input.txt | awk -F' ' '{print$1}'

OR

, предложенный Сергеем Колодяжным

awk -F'[>|]' '{print substr($2,2)}' input.txt
3
ответ дан 18 July 2018 в 13:26

Прежде всего, я считаю, что это выход diff -y, поэтому вы можете также включить <.

Мы можем использовать grep только для этого:

grep -Po "(?<=(\||<|>)\s).*" file.txt .* Ищите что-нибудь в любое время. (?<=(\||<|>)\s), который находится за одним из них (| или < или >), за которым следует пробел.

более понятная версия:

grep -Po '(?<=[<|>]\s).*' file.txt

Или используя grep и cut, как вы пытались:

grep -Eo "(<|>|\|).*" file.txt | cut -f2 -d' ' .* Ищите что-нибудь в любое время. -o Распечатайте только соответствующую часть (?<=(\||<|>)\s), которая находится за одним из них (| или < ] или >), за которым следует пробел. .* каждая вещь & amp; в любое время повторяется

Который доводит нас до этой точки:

enter code here > Aminobenzoate | Atrazine | Bacterial | Benzoate | beta-Lactam > Biosynthesis | Caprolactam | Carbapenem

, а затем используя cut, мы получаем второе поле, которое является нашей строкой, которая:

Aminobenzoate Atrazine Bacterial Benzoate beta-Lactam Biosynthesis Caprolactam Carbapenem
3
ответ дан 18 July 2018 в 13:26

Perl

Вот один однострочный perl, который выполняет задание:

$ perl -ne 's/^.*[|>]\ //;print' inp.txt Aminobenzoate Atrazine Bacterial Benzoate beta-Lactam Biosynthesis Caprolactam Carbapenem

Или даже короче, как предложила Матия Налис в комментариях

perl -pe 's/^.*[|>]\ //' inp.txt

В основном он принимает и удаляет все, начиная с начала строки, до | или >, а затем печатает вещи.

Альтернативное седло с группировкой

Если вы еще не заметили, все ответы здесь основаны на идее удаления ведущей информации. То, что мы также можем сделать, - это то, что мы хотим, и заменим целую строку на это.

Возьмем, к примеру, это sed

$ sed 's/^.*[>|] \(.*$\)/\1/' inp.txt Aminobenzoate Atrazine Bacterial Benzoate beta-Lactam Biosynthesis Caprolactam Carbapenem

Что происходит, так это то, что все, что находится внутри \( и \), будет рассматриваться как одно целое и ссылаться на \1. Эта команда в основном говорит: «Возьмите все, что приходит после > или | плюс пробел, и сделайте его как одну группу, и замените эту целую строку тем, что мы помещаем в эту группу \1.

[ ! d12]

Python

Хотя скрипты python могут быть немного длиннее, они, как правило, более читабельны и явны. Вот что мы можем сделать с скриптом Python 3:

#!/usr/bin/env python3 import sys import re with open(sys.argv[1]) as fd: for line in fd: print(re.split("<|>|\|",line.strip())[1].strip())

] Ключевыми идеями здесь являются следующие:

мы открываем любой файл в качестве аргумента командной строки, который мы перебираем по каждой строке файла, используя функцию re.split(), мы разбиваем каждую строку на список, используя > или | или > в качестве разделителя. Затем мы извлекаем второй (индекс [1] в списке, так как список начинается с индекса 0) в этом списке, а с помощью функции strip() удаляются ведущие и конечные пробелы. Все эти действия re.split() и извлечения списка происходят в функции print(), поэтому, как только все эти операции будут выполнены, мы получим желаемую строку вывода и перейдем к обработке следующей строки

Если мы разыскивается to, мы всегда могли бы перетащить все в однострочный слой:

$ python -c 'import re,sys;print("\n".join([ re.split("<|>|\|",l.strip())[1].strip() for l in sys.stdin]))' < inp.txt Aminobenzoate Atrazine Bacterial Benzoate beta-Lactam Biosynthesis Caprolactam Carbapenem

Другие примечания:

мы открываем любой файл в качестве аргумента командной строки
3
ответ дан 18 July 2018 в 13:26

Я бы предложил использовать sed для этого:

sed 's/.*[|>] *//'

Это работает для вашего примера, но вам может понадобиться его адаптировать, в зависимости от того, что делать с линиями без каких-либо | или >. Если они должны быть полностью удалены, используйте

sed -n 's/.*[|>] *//p'

. Это означает, что по умолчанию не выводится (опция -n), но печатайте строку (p), если команда s выполнить замену.

5
ответ дан 18 July 2018 в 13:26

Наименьшая модификация вашей текущей команды заключалась бы в замене вашего упоминания на буквенный символ | в вашем регулярном выражении ссылкой на класс символов, содержащий как |, так и >, [|>], которые будет соответствовать любому из них:

grep -o ' [|>].*$'| cut -c5-

Другие исследовали реализации awk, sed и perl, но ваша реализация grep также может быть улучшена.

Например, вы можете избавиться от команды cut следующими способами:

с помощью флага Perl \K: grep -Po '[>|]\s*\K.* с помощью внешнего вида PCRE: grep -Po '(?<=[|>]\s).*' обратите внимание, что это будет работать только с фиксированным количеством пробелов между разделителем и целевым словом, так как двигатели PCRE не требуются для реализации переменной ширины lookbehind и обычно этого не делают.
0
ответ дан 24 July 2018 в 20:10
  • 1
    Большое вам спасибо за вашу помощь в решении вопроса. – Rhea 13 May 2017 в 14:44

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

awk -F'[>|]' '{print$2}' input.txt | awk -F' ' '{print$1}'

OR

, предложенный Сергеем Колодяжным

awk -F'[>|]' '{print substr($2,2)}' input.txt
3
ответ дан 24 July 2018 в 20:10
  • 1
    Это бесполезное использование cat. – karel 12 May 2017 в 09:36
  • 2
    ОК, прежде всего, вам не нужно cat файл в awk через канал. awk может принимать аргументы командной строки просто отлично, и вам не нужно объявлять пространство как разделитель для awk во второй команде. Фактически, три части заключены в одну приятную команду: awk -F'[>|]' '{print substr($2,2)}' input.txt – Sergiy Kolodyazhnyy 12 May 2017 в 09:36
  • 3
    @ СергийКолодяжный Спасибо. Я не знаю об этом. Давая ответ, я тоже учусь. Я попытался найти около '{print substr($2,2)}', но я не мог, поэтому мне пришлось использовать cat и вторую команду awk. – d a i s y 12 May 2017 в 09:40
  • 4
    @daisy Замечательно, что вы учитесь и пытаетесь ответить. Я был там, начинал так же, как ты. Это в основном использует & gt; и | как разделители, и, таким образом, делает наши искомые слова вторым «столбцом». во входном файле. Это также означает, что столбец будет иметь ведущий символ пробела, поэтому мы печатаем подстроку этого столбца, начиная с индекса 2 всего столбца. Продолжайте учиться и не стесняйтесь редактировать свой ответ, чтобы включить это предложение. Я ничего против этого – Sergiy Kolodyazhnyy 12 May 2017 в 10:00

Прежде всего, я считаю, что это выход diff -y, поэтому вы можете также включить <.

Мы можем использовать grep только для этого:

grep -Po "(?<=(\||<|>)\s).*" file.txt .* Ищите что-нибудь в любое время. (?<=(\||<|>)\s), который находится за одним из них (| или < или >), за которым следует пробел.

более понятная версия:

grep -Po '(?<=[<|>]\s).*' file.txt

Или используя grep и cut, как вы пытались:

grep -Eo "(<|>|\|).*" file.txt | cut -f2 -d' ' .* Ищите что-нибудь в любое время. -o Распечатайте только соответствующую часть (?<=(\||<|>)\s), которая находится за одним из них (| или < ] или >), за которым следует пробел. .* каждая вещь & amp; в любое время повторяется

Который доводит нас до этой точки:

enter code here > Aminobenzoate | Atrazine | Bacterial | Benzoate | beta-Lactam > Biosynthesis | Caprolactam | Carbapenem

, а затем используя cut, мы получаем второе поле, которое является нашей строкой, которая:

Aminobenzoate Atrazine Bacterial Benzoate beta-Lactam Biosynthesis Caprolactam Carbapenem
3
ответ дан 24 July 2018 в 20:10
  • 1
    Как насчет grep -Po '[<|>]\s*\K.*'? нет необходимости в cut – steeldriver 12 May 2017 в 13:10
  • 2
    @steeldriver Спасибо, я добавляю решение с "look behind" тоже;) но ваш более ясный :) – Ravexina 12 May 2017 в 13:17

Perl

Вот один однострочный perl, который выполняет задание:

$ perl -ne 's/^.*[|>]\ //;print' inp.txt Aminobenzoate Atrazine Bacterial Benzoate beta-Lactam Biosynthesis Caprolactam Carbapenem

Или даже короче, как предложила Матия Налис в комментариях

perl -pe 's/^.*[|>]\ //' inp.txt

В основном он принимает и удаляет все, начиная с начала строки, до | или >, а затем печатает вещи.

Альтернативное седло с группировкой

Если вы еще не заметили, все ответы здесь основаны на идее удаления ведущей информации. То, что мы также можем сделать, - это то, что мы хотим, и заменим целую строку на это.

Возьмем, к примеру, это sed

$ sed 's/^.*[>|] \(.*$\)/\1/' inp.txt Aminobenzoate Atrazine Bacterial Benzoate beta-Lactam Biosynthesis Caprolactam Carbapenem

Что происходит, так это то, что все, что находится внутри \( и \), будет рассматриваться как одно целое и ссылаться на \1. Эта команда в основном говорит: «Возьмите все, что приходит после > или | плюс пробел, и сделайте его как одну группу, и замените эту целую строку тем, что мы помещаем в эту группу \1.

[ ! d12]

Python

Хотя скрипты python могут быть немного длиннее, они, как правило, более читабельны и явны. Вот что мы можем сделать с скриптом Python 3:

#!/usr/bin/env python3 import sys import re with open(sys.argv[1]) as fd: for line in fd: print(re.split("<|>|\|",line.strip())[1].strip())

] Ключевыми идеями здесь являются следующие:

мы открываем любой файл в качестве аргумента командной строки, который мы перебираем по каждой строке файла, используя функцию re.split(), мы разбиваем каждую строку на список, используя > или | или > в качестве разделителя. Затем мы извлекаем второй (индекс [1] в списке, так как список начинается с индекса 0) в этом списке, а с помощью функции strip() удаляются ведущие и конечные пробелы. Все эти действия re.split() и извлечения списка происходят в функции print(), поэтому, как только все эти операции будут выполнены, мы получим желаемую строку вывода и перейдем к обработке следующей строки

Если мы разыскивается to, мы всегда могли бы перетащить все в однострочный слой:

$ python -c 'import re,sys;print("\n".join([ re.split("<|>|\|",l.strip())[1].strip() for l in sys.stdin]))' < inp.txt Aminobenzoate Atrazine Bacterial Benzoate beta-Lactam Biosynthesis Caprolactam Carbapenem

Другие примечания:

мы открываем любой файл в качестве аргумента командной строки
3
ответ дан 24 July 2018 в 20:10
  • 1
    BTW, perl -ne с print в конце лучше написано так же, как perl -pe (без конца print в конце). Кроме того, в вашем примере sed есть дополнительные (ненужные) '$ – Matija Nalis 12 May 2017 в 12:17
  • 2
    Вы можете прокручивать пробел в разделитель полей и избегать sub, например. [F2] – steeldriver 12 May 2017 в 13:14
  • 3
    @MatijaNalis Спасибо за предложения. Включили уже – Sergiy Kolodyazhnyy 12 May 2017 в 17:12
  • 4
    @steeldriver Спасибо! Это хорошо знать. Я на самом деле пытался это понять. Когда я попробовал, он почему-то потянул все противоположные линии. знак равно – Terrance 12 May 2017 в 17:24

Я бы предложил использовать sed для этого:

sed 's/.*[|>] *//'

Это работает для вашего примера, но вам может понадобиться его адаптировать, в зависимости от того, что делать с линиями без каких-либо | или >. Если они должны быть полностью удалены, используйте

sed -n 's/.*[|>] *//p'

. Это означает, что по умолчанию не выводится (опция -n), но печатайте строку (p), если команда s выполнить замену.

5
ответ дан 24 July 2018 в 20:10
  • 1
    Я использовал этот запрос (sed 's /.* [| & gt;] * //'), и я получил свой ответ. – Rhea 13 May 2017 в 14:45

Другие вопросы по тегам:

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