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

У меня есть следующий вход (тысяча строк). Я хочу, чтобы команда 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 

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

 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 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 при совпадении.

  • Почему мои изменения в файле sshd_config не сохраняются?
  • Можно ли использовать sed для генерации файла нагрузки для таблицы фактов поиска даты?
  • Как извлечь первую часть имен файлов с тем же суффиксом?
  • Печатать слово, которое не содержит символа
  • Замените строку в файле на другую, где оба сохраняются в переменных
  • Удалить строки со значением ниже (или выше) порога
  • почему этот простой скрипт sed не работал »nginx -V 2> & 1 | sed -r 's / - / \\ n / g' "
  • Как я могу избежать специальных символов в команде sed?
  • Обрезка одной части, если она равна другой части?
  • исключая символ перед определенным символом в sed
  • Сменная строка, содержащая шаблон со следующей строкой
  • sed - как удалить все строки, которые не совпадают
  • Linux и Unix - лучшая ОС в мире.