Я пытаюсь удалить дубликаты в списке билетов Jira, которые следуют следующему синтаксису:
XXXX-12345: a description
где 12345 — это шаблон типа [0-9]+, а XXXX — константа. Например, следующий список:
XXXX-1111: a description
XXXX-2222: another description
XXXX-1111: yet another description
должно очищаться так:
XXXX-1111: a description
XXXX-2222: another description
Я пытался использовать sed
, но то, что я работал на Mac, не работало на Linux. Думаю, с awk
было бы проще, но я не эксперт ни по одному из них.
Я пытался:
sed -r '$!N; /^XXXX-[0-9]+\n\1/!P; D' file
Можете ли вы показать свой код попытки?
@Тор Спасибо! это сработало. Не могли бы вы объяснить мне команду, пожалуйста? Я понимаю идею использования awk '!seen', но я не понимаю, почему $1 или как он идентифицирует шаблон в моем случае использования.
@JuanVega: awk разбивает каждую строку на поля в соответствии с тем, что установлено для FS
, по умолчанию это последовательности пробелов и табуляции. Это разбиение устанавливает позиционные переменные $1
, $2
, ... соответственно, поэтому $1
- это первое поле, до первого пробела/табуляции
@anubhava Я пытался использовать sed -r '$!N; /^XXXX-[0-9]+\n\1/!P; D'
, так как нашел другой ответ, где он использовался для удаления повторяющихся строк. В исходном ответе вместо XXXX-[0-9]+
было (.*)
. Но я точно не понимаю, как это работает, потому что это не работает.
@ Тор Хорошо, теперь я понял. Так что в моем случае это работает в основном потому, что после :
всегда есть пробел. Поэтому, если я хочу, чтобы это работало, разбивая по первому двоеточию, чтобы избежать строк без пробелов, я должен использовать awk -F ':' '!seen[$1]
, верно? Я был сбит с толку, потому что при поиске информации я видел варианты использования, в которых использовался 0 долларов вместо 1.
@JuanVega: Вы можете просто использовать awk '!seen[$1]++' file
Если цифры - единственное, что определяет дубликат, вы можете сделать:
awk -F: '{split($1,arr,/-/); if (seen[arr[2]]++) next} 1' file
Если XXXX
всегда один и тот же, вы можете упростить до:
awk -F: '!seen[$1]++' file
Либо печатает:
XXXX-1111: a description
XXXX-2222: another description
Спасибо! Я держу это в уме, если в какой-то момент персонажи изменятся.
Этот простой awk
должен получить результат:
awk '!seen[$1]++' file
XXXX-1111: a description
XXXX-2222: another description
Да, в итоге я использовал его, как и предложил @Thor. Спасибо!
Это может сработать для вас (GNU sed):
sed -nE 'G;/^([^:]*:).*\n\1/d;P;h' file
-nE
включить явную печать и расширенные регулярные выражения.G
добавлять уникальные строки из пробела в текущую строку./^([^:]*:).*\n\1/d
Если текущий ключ линии уже существует, удалите его.P
в противном случае напечатать текущую строку иh
хранить уникальные линии в трюмеН.Б. Ваше решение sed будет работать (не как есть, а с некоторой настройкой), но только если файлы будут отсортированы по ключу.
sed -E 'N;/^([^:]*:).*\n\1/!P;D' file
Я не добавлял код, но да, я сначала отсортировал строки, прежде чем использовать решение no. Мне любопытно, решение, которое вы предлагаете, мне нужно настроить? Я не эксперт по выражениям регулярных выражений, так что же делает это регулярное выражение, чтобы использовать только часть XXXX-1234 в сравнении?
Спасибо за объяснение!
@JuanVega в регулярном выражении вы можете группировать совпадающие части, заключая их в круглые скобки. Затем вы можете обратиться к этим группам по обратной ссылке, которая нумеруется, начиная с самой левой скобки. например /(aaa)(bbb)\1\2/ будет соответствовать строке aaabbbbaaabbb, а /((aaa)bbb)\1\2/' будет соответствовать строке aaabbbbaaabbbbaaa. Таким образом, регулярное выражение /^([^:]*:).*\n\1/ будет соответствовать одному и тому же ключу дважды, а в приведенном выше решении удалит эту строку. HTH Кстати, первое решение работает отсортировано или не отсортировано, второе только при сортировке
Замена
$0
на$1
в принятом ответе на этот связанный с вопрос должна помочь.