Возможен ли этот сценарий извлечения текста в оболочке linux bash?

Допустим, мой текстовый файл такой

Человек1 : фильм1
(пробел и табуляция) : фильм 2
(пробел и табуляция) : фильм 3
(пробел и табуляция) : фильм 4

Я хочу найти для определенного фильма актера. Итак, вот как я собираюсь это сделать.

У актеров grep cat | grep 'фильм3'

Это даст мне строку 3, которая является пустой строкой до появления фильма 3. Итак, если каким-то образом я могу получить первую строку перед этой конкретной строкой, которая следует этому шаблону

grep '^[^ \t].' (не начинается с пробела)

это должна быть строка с именем актера в этом фильме (мне все равно, какой фильм там)

Есть ли какая-либо комбинация sed/grep/awk, которая может помочь мне сделать это в оболочке? Надеюсь вопрос ясен.


person Dude    schedule 29.06.2014    source источник


Ответы (4)


Билл Мюррей ‹- День сурка ‹- grep с режимом Perl Magic

Это немного сложно, но вы можете использовать это:

grep -P "(?sm)^\S+[^:\r\n]*?(?=\s*:(?:(?!^\S).)*?Groundhog Day)" mymoviefile

См. демонстрацию.

  • -P активирует режим Perl
  • (?sm) включает два модификатора режима:
  • s активирует режим DOTALL, позволяя точкам совпадать на линиях
  • m включает многострочный режим, позволяя ^ и $ совпадать в каждой строке
  • Якорь ^ утверждает, что мы находимся в начале строки
  • \S+ соответствует одному или нескольким не пробельным символам
  • [^:\r\n]*? лениво соответствует любым символам без двоеточия и новой строки, вплоть до ...
  • точка, в которой опережающее (?=\s*:(?:(?!^\S).)*?Groundhog Day) может утверждать, не потребляя символы, что следует...
  • \s*: необязательные пробелы и двоеточие
  • затем (?:(?!^\S).)* ноль или более символов, которые не являются непробельными символами в начале строки, лениво сопоставляя до...
  • Groundhog Day название фильма!

Справочник

person zx81    schedule 29.06.2014
comment
Я попытался запустить его. Это не работает. Вот сообщение об ошибке grep: нераспознанный символ после (? или (?-. Я пытаюсь его отладить, но, поскольку это очень сложно, и я не знаю половины вещей, которые вы использовали здесь, я думаю, что буду нужна ваша дальнейшая помощь. : ^ D - person Dude; 29.06.2014
comment
Добавил твик и твик, посмотри. :) - person zx81; 29.06.2014
comment
Спасибо за помощь. Но это определенно не для слабонервных. - person Dude; 29.06.2014
comment
Закончил объяснение. ` это определенно не для слабонервных` Вы правы, это далеко не очевидно, но с объяснением, я уверен, вы сможете это понять. Это работает? - person zx81; 29.06.2014
comment
Спасибо, чувак, рад, что помог! :) - person zx81; 29.06.2014
comment
После этого объяснения я должен тебе как минимум 50-60 репутации! :) - person Dude; 29.06.2014
comment
Нет, это было настоящее удовольствие, пожалуйста! :) Если вы хотите сделать мне (или вам) одолжение, изучите еще несколько классных регулярных выражений! :) Например, в правой панели моего профиля есть несколько интересных вопросов, Часто задаваемые вопросы по регулярным выражениям также хороши, а затем ответы некоторых богов регулярных выражений здесь (нажмите на самых популярных пользователей за все время в теге регулярных выражений) или таких сайтов, как регулярные-выражения.info и rexegg... Регулярные выражения круто, чувак! :) - person zx81; 29.06.2014

Я бы сделал это с помощью awk, если бы правильно понял проблему:

 awk -F: -v s="$search" '$1~/\S/{p=$1}$2~s{print $1 FS $2}' file

тест с movie 3:

kent$ cat f
Person1 : movie1
          : movie 2
          : movie 3
          : movie 4

в приведенном выше файле есть ведущие пробелы/вкладки

kent$  awk -F: -v s="movie 3" '$1~/\S/{p=$1}$2~s{print p FS $2}' f
Person1 : movie 3
person Kent    schedule 29.06.2014
comment
Я создал такой же файл, как и ваш, без пробела в строке с person1: movie1. и я выполнил точную команду, которую вы мне дали. Это дало только это (начало строки): фильм 3. - person Dude; 29.06.2014
comment
Я на линуксе. Ожидается, что он будет работать там, если вы запустили его на Mac? - person Dude; 29.06.2014
comment
@ Чувак, у меня только линукс. Я думаю, поскольку ваша версия gawk ниже моей, вы можете попробовать: awk ... '$1~/[^ \t]/{....}' - person Kent; 29.06.2014
comment
Да, это сработало. Если вы не возражаете, не могли бы вы кратко объяснить регулярное выражение. - person Dude; 29.06.2014
comment
@Dude, регулярное выражение просто соответствует строке ($ 1, первый столбец), если она содержит какой-либо непустой символ. Такая проблема типична для awk. grep великолепен, но здесь он не подходит для этого (мое мнение) - person Kent; 29.06.2014

Это может сработать для вас (GNU sed):

sed -n '/^\S/h;/movie 3/{H;x;s/:.*:/:/p}' file

Используйте переключатель -n, чтобы предоставить grep как природу. Сохраните человека в резервном пространстве и добавьте к нему фильм. Затем удалите ненужный текст и распечатайте.

person potong    schedule 29.06.2014

Это немного неясно, но выполните работу:

awk '/^[^ ]/{p=0} /Person1/{p=1} p'

Пример:

Входной файл:

Person1 : movie1
    : movie 2
    : movie 3
    : movie 4
Person2 : movie 5
    : movie 6

Исполнение:

awk '/^[^ ]/{p=0} /Person1/{p=1} p' file
Person1 : movie1
    : movie 2
    : movie 3
    : movie 4

awk '/^[^ ]/{p=0} /Person2/{p=1} p' file
Person2 : movie 5
    : movie 6

OBS: вывод в командной строке имеет отступ.

Объяснение:

  1. Если строка не начинается с пробела, устанавливает p=0
  2. Если строка содержит Person1 устанавливает p=1
  3. если p=1, то выведите (эта часть неясна)

Можно сделать и в perl:

perl -ne '/^\w+/ && {$p=0}; /Person1/ && {$p=1}; $p && {print}' 
person Tiago Lopo    schedule 29.06.2014