Unix/Linux Команда для захвата слова, если другая строка содержит слово (обе строки имеют общий атрибут)

perl -F, -lane '
   exists $h{$F[0]} or $h[$h{$F[0]}=@h]=$_;
   $h=$_; /,false$/ or $_=$h for $h[$h{$F[0]}];
   END{ print for @h; }
' duplicates.file

Структуры данных:

  • Хэш %h, чьи ключи являются первыми полями. (AAA, BBB, CCC и т. д. )и соответствующие значения являются числами, указывающими порядок, в котором встречались ключи. Таким образом, например, клавиша AAA => 0, клавиша BBB => 1, клавиша CCC => 2.
  • Массив @h, элементами которого являются строки, содержащиеся в порядке печати. Таким образом, если в данных найдены и истина, и ложь, то в массив попадет ложное значение. OTW, если есть один тип данных, то он будет присутствовать.

Другой способ — использовать GNU sed:

sed -Ee '
   G
   /^([^,]*),(false|true)\n(.*\n)?\1,\2(\n|$)/ba
   /^([^,]*)(,true)\n(.*\n)?\1,false(\n|$)/ba
   /^([^,]*)(,false)\n((.*\n)?)\1,true(\n|$)/{
      s//\3\1\2\5/;h;ba
   }
   s/([^\n]*)\n(.*)$/\2\n\1/;s/^\n*//
   h;:a;$!d;g
' duplicates.file

FWIW, код, эквивалентный POSIX для приведенного выше кода GNU -sed, указан ниже:

sed -e '
   G

   /^\([^,]*\),\(false\)\n\(.*\n\)\{0,1\}\1,\2$/ba
   /^\([^,]*\),\(false\)\n\(.*\n\)\{0,1\}\1,\2\n/ba

   /^\([^,]*\),\(true\)\n\(.*\n\)\{0,1\}\1,\2$/ba
   /^\([^,]*\),\(true\)\n\(.*\n\)\{0,1\}\1,\2\n/ba

   /^\([^,]*\),true\n\(.*\n\)\{0,1\}\1,false$/ba
   /^\([^,]*\),true\n\(.*\n\)\{0,1\}\1,false\n/ba

   /^\([^,]*\)\(,false\)\n\(\(.*\n\)\{0,1\}\)\1,true$/{
      s//\3\1\2/
      h
      ba
   }
   /^\([^,]*\)\(,false\)\n\(\(.*\n\)\{0,1\}\)\1,true\n/{
      s//\3\1\2\n/
      h
      ba
   }

   y/\n_/_\n/
   s/\([^_]*\)_\(.*\)$/\2_\1/;s/^_*//
   y/\n_/_\n/

   h;:a;$!d;g
' duplicates.file

Пояснение

  • В этом методе мы сохраняем результат, который будет окончательно напечатан, в ячейке удержания.
  • Для каждой прочитанной строки мы добавляем пространство удержания к пространству шаблонов для проверки текущей строки относительно -и -относительно существующего состояния пространства удержания.
  • Во время этого сравнения могут произойти 5 вещей :
    • a )Текущая строка где-то совпадает с линией удержания и ложь :ложь.
      • [ДЕЙСТВИЕ] Поскольку обнаружено такое же ложное состояние, ничего не делать.
    • b )Текущая строка где-то совпадает с линией удержания и true :true.
      • [ДЕЙСТВИЕ] Поскольку найдено такое же истинное состояние, ничего не делать.
    • c )Текущая строка где-то совпадает с линией удержания и true :false.
      • [ДЕЙСТВИЕ] Поскольку ложное состояние уже существует, ничего не делайте.
    • d )Текущая строка совпадает где-то в строке удержания и false :true.
      • [ДЕЙСТВИЕ] Это требует некоторой работы, поскольку нам нужно заменить ложную строку в той же самой позиции, где находится истинная.
    • e )Текущая строка НЕ ​​СООТВЕТСТВУЕТ нигде в линии удержания.
      • [ДЕЙСТВИЕ] Переместить текущую строку в конец.

Результаты

AA,false
BB,false
CC,false
DD,true
1
22.10.2019, 18:21
3 ответа

Для этого можно использовать awk:

Предполагая, что Trn-statusвсегда предшествуетTECHNICAL EXCEPTION

awk  -F'[\;\=]' '
    { if ( $0 ~ /Trn-status: INCOMPLETE/ ) checkid[$2]=$2 ;
      if ( $2 == checkid[$2] ) {
         if ( $0 ~ /TECHNICAL EXCEPTION/ ) print checkid[$2]
      }
    }' logfile

Пояснение:

  • -F'[\;\=]'используйте либо ;, либо =в качестве разделителей полей; использование квадратных скобок позволяет вам определить несколько разделителей полей, точка с запятой и знак равенства являются специальными символами для awk, поэтому вам нужно экранировать их обратной косой чертой
  • первая строка:$0представляет собой всю строку, ~представляет собой (подчиненный )оператор сопоставления с образцом и /PATTERN/строку поиска. Поэтому, если мы находим Trn-status: INCOMPLETEв строке, мы сохраняем поле ID (номер два, разделенное ;и =от других полей )в массиве checkid, где индекс — это имя Сам ID(awkпозволяет использовать строки в качестве индексных счетчиков)
  • вторая строка :если мы найдем ID в другой строке...
  • третья строка :проверить наличие TECHNICAL EXCEPTIONи распечатать идентификатор, если да
  • (logfileимя вашего файла)
1
27.01.2020, 23:40

Эта задача слишком сложна для grep, но можно использовать sed, например:

sed '/Trn-status:/h;/\\"message\\":\\"TECHNICAL EXCEPTION\\"/!d;G;/Trn-status: INCOMPLETE/!d;s/.*"errorCode\\":\\"//;s/\\".*//' yourfile
  • /Trn-status:/hчтобы всегда сохранять последнюю Trn-statusстроку в ячейке хранения
  • /\\"message\\":\\"TECHNICAL EXCEPTION\\"/!dозначает dудаление всех строк без(!)заданного шаблона. Обратите внимание, что обратную косую черту необходимо экранировать другой обратной косой чертой
  • .
  • Остальное для скрипта обрабатывается только для TECHNICAL EXCEPTIONсообщений, но теперь нам нужно убедиться, что Trn-statusравно INCOMPLETE, поэтому мы добавляем пробел с Gи delete, если мы не не найтиTrn-status: INCOMPLETE
  • Теперь просто удалите часть перед(s/.*"errorCode\\":\\"//)и после(s/\\".*//)кода, который вы ищете.
0
27.01.2020, 23:40

Бессовестно опираясь на хороший урок @Fiximan по множественным разделителям для awk.

Предположение о неопределенном содержании данных, поэтому итерация по полям для поиска фактического кода ошибки.

awk  -F'[:;,=]' '{
  if ( $0 ~ /Trn-status: INCOMPLETE/ ) checkid[$2]=$2 ;
    if ( $2 == checkid[$2] && $0 ~ /TECHNICAL EXCEPTION/ ) {
      for (i=1; i<=NF; i++) {if ( $i ~ "\"errorCode") print $(i+1), $2
    }
  }
}' logfile | sed "s/[\\\"]//g"
0
27.01.2020, 23:40

Теги

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