Слияние дублированных строк, которые имеют одинаковые первые три поля

У меня есть следующий вход (тысяча строк). Я хочу, чтобы команда sed объединила дублированные строки с теми же первыми тремя полями, которые добавили только разные поля или удалили «N / A»:

 D04005;4;279;0;0;SSM-4-1 D04005;5;40;0;0;SSM-5-1 LE040A;1;363;(26.3);N/A;SM-1-1 LE040A;1;363;(27.4);N/A;SM-1-2 

Ожидаемый результат:

  • Делайте более длинные строки из подстрок, сохраняя новую строку между каждой строкой
  • Как извлечь несколько строк, разделенных запятой из файла журнала?
  • Использование perl для изменения документа LaTeX
  • Регулярное выражение находит 3 или 4 числа
  • Как заменить только N-е вхождение шаблона в файл?
  • Как я могу удалить поле nth в mth с помощью команды awk?
  •  D04005;4;279;0;0;SSM-4-1 D04005;5;40;0;0;SSM-5-1 LE040A;1;363;(26.3);(27.4);SM-1-1/SM-1-2 

  • Удаление строк путем сопоставления только 3-го и 4-го символов
  • Заменить текст быстро в очень большом файле
  • У sed есть функция, превосходящая awk?
  • Как отобразить n-й результат команды ls?
  • Передача разобранного вывода sed для поиска (в этом направлении)
  • Получить содержимое файла из первого экземпляра в последний экземпляр некоторой произвольной строки
  • 3 Solutions collect form web for “Слияние дублированных строк, которые имеют одинаковые первые три поля”

     sed ':n s|;N/A;|;|g;$!N s|^\(\([^;]*;\)\{3\}\)\(.*\)\n\1|\1\3;|;tn P;D ' <<\IN D04005;4;279;0;0;SSM-4-1 D04005;5;40;0;0;SSM-5-1 LE040A;1;363;(26.3);N/A;SM-1-1 LE040A;1;363;(27.4);N/A;SM-1-2 LE040A;1;363;(28.5);N/A;SM-1-3 LE040A;1;363;(29.6);N/A;SM-1-4 IN 

    Это будет продолжать отводить назад к каждому последовательному входу, объединяя только хвосты для каждого.

    Это портативно написано, но немного легче писать, если вы можете использовать -E расширенные регулярные выражения (как вы могли бы с версиями BSD или GNU)

     sed -E ':n s|;N/A;|;|g;$!N s|^(([^;]*;){3})(.*)\n\1|\1\3;|;tn P;D' 

    Если вы хотите все это на одной строке:

     sed -Ee:n -e's|;N/A;|;|g;$!N;s|^(([^;]*;){3})(.*)\n\1|\1\3;|;tn' -eP\;D 

    … будет работать, но я никогда не очень любил однострочники

    В любом случае, выход из первого там:

    ВЫВОД

     D04005;4;279;0;0;SSM-4-1 D04005;5;40;0;0;SSM-5-1 LE040A;1;363;(26.3);SM-1-1;(27.4);SM-1-2;(28.5);SM-1-3;(29.6);SM-1-4 

    Чтобы также переместить любое конечное поле, начинающееся с символа / SM- до SM- строки, и для разделения каждого из них с / , я считаю, что следующее должно работать:

     sed -E ':n s|;N/A;|;|g s|;(SM-[^;]*)$|/\1|;$!N s|^(([^;]*;){3})(.*)\n\1|\1\3;|;tn P;D' 

    Вы знаете, кстати, это может стать намного проще – и намного быстрее – если вы можете быть более ясными и более конкретными о том, что вам нужно. Для меня не похоже, что вы хотите объединить только три первых одинаковых поля на любые две последовательные строки и удалить поле, которое соответствует N/A из любой строки, и затем переместить SM- поля в хвост любого линия. Скорее, для меня это похоже на то, что все эти индивидуальные задания, которые вы назовете, на самом деле одно и то же, и что вы действительно хотите что-то вроде:

    • Если строка ввода найдена с тремя полями с буквой с буквой, с разделителями с запятой, то поле с плавающей точкой в ​​скобках, за которым следует другой разделитель двоеточия, затем поле N/A , мы должны сделать следующее:
      1. Проверьте, соответствует ли следующая строка этому описанию, и, если так, сравните первые три поля для текущей строки и следующей.
      2. Если совпадение найдено, сохраните только последнее поле из следующей строки, а затем повторите попытку, чтобы повторить попытку.
      3. Независимо от того, всегда удаляйте поле, которое соответствует N/A , и заменяет последнее ; с / .
    • Независимо от того, напечатайте все, что остается в stdout.

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

    Если я прав, то может работать следующее:

     sed ' \|;N/A;|!b s||/|;$!N \|^\(.*(\)\(.*)\)\(.*\)\(\n\1\)\(.*)\)|!P s||\4\2;(\5\3|;D ' <<\IN D04005;4;279;0;0;SSM-4-1 D04005;5;40;0;0;SSM-5-1 LE040A;1;363;(26.3);N/A;SM-1-1 LE040A;1;363;(27.4);N/A;SM-1-2 LE040A;1;363;(28.5);N/A;SM-1-3 LE040A;1;363;(29.6);N/A;SM-1-4 IN 

     D04005;4;279;0;0;SSM-4-1 D04005;5;40;0;0;SSM-5-1 LE040A;1;363;(26.3);(27.4);(28.5);(29.6)/SM-1-1/SM-1-2/SM-1-3/SM-1-4 

    … Здесь это -E на одной строке …

     sed -e'\|;N/A;|!b' -e's||/|;$!N;\|^\(.*(\)\(.*)\)\(.*\)\(\n\1\)\(.*)\)|!P;s||\4\2;(\5\3|;D' 

    … или in -E расширенный синтаксис …

     sed -Ee'\|;N/A;|!b' -e's||/|;$!N;\|^(.*\()(.*\))(.*)(\n\1)(.*\))|!P;s||\4\2(\5\3|;D' 

    TXR:

     @(repeat) @ (cases) @id;@f2;@f3;@val1;@nil;@sm1 @id;@f2;@f3;@val2;@nil;@sm2 @ (do (put-line `@id;@f2;@f3;@val1;@val2;@sm1/@sm2`)) @ (or) @line @ (do (put-line line)) @ (end) @(end) $ txr data.txr data D04005;4;279;0;0;SSM-4-1 D04005;5;40;0;0;SSM-5-1 LE040A;1;363;(26.3);(27.4);SM-1-1/SM-1-2 
     sed -r ':a;N;s!;N/A!!g;s/^(([^;]*;){3})(.*)\n\1/\1\3;/;T;s!^(([^S][^;]*;){3,})(S*SM-[^;]*);(([^S][^;]*;){1,})(.*)!\1\4\3/\6!;ta' inputfile 

    Несмотря на то, что подразумеваемая математика вашего комментария только для 6 полей на выходе предполагает, что есть только пары, это циклическая версия с изменениями вывода SM-1-1 / SM-1-2 при совпадении.

    Linux и Unix - лучшая ОС в мире.