Как удалить повторяющиеся значения в одной строке?

Сохраните вывод в 2 файла и используйте приведенную ниже команду для достижения результата, как указано

cat file1 file2|sed  '/Month/d'| sed "s/:$//g"| sed '1i Month  Day  Time      SystemMessage'

Month  Day  Time      SystemMessage
Mar    30   02:50:56  SHUTDOWN_TIME
Mar    30   13:13:28  SHUTDOWN_TIME
Apr    1    17:27:48  SHUTDOWN_TIME
Apr    1    23:59:37  SHUTDOWN_TIME
Apr    10   17:08:10  SHUTDOWN_TIME
Apr    10   22:59:13  SHUTDOWN_TIME
Apr    11   19:13:43  SHUTDOWN_TIME
Apr    2    16:33:50  SHUTDOWN_TIME
Apr    3    00:13:58  SHUTDOWN_TIME
Apr    3    16:54:22  SHUTDOWN_TIME
Apr    3    23:36:55  SHUTDOWN_TIME
Apr    4    17:00:40  SHUTDOWN_TIME
Apr    5    17:00:50  SHUTDOWN_TIME
Apr    8    17:41:18  SHUTDOWN_TIME
Apr    8    23:41:05  SHUTDOWN_TIME
Apr    9    17:19:33  SHUTDOWN_TIME
Apr    9    23:23:18  SHUTDOWN_TIME
Mar    30   12:37:12  BOOT_TIME
Apr    1    10:09:12  BOOT_TIME
Apr    1    21:45:41  BOOT_TIME
Apr    10   09:38:12  BOOT_TIME
Apr    10   19:53:06  BOOT_TIME
Apr    11   12:02:02  BOOT_TIME
Apr    12   09:33:21  BOOT_TIME
Apr    2    10:19:19  BOOT_TIME
Apr    2    22:54:34  BOOT_TIME
Apr    3    09:56:02  BOOT_TIME
Apr    3    21:09:25  BOOT_TIME
Apr    4    10:00:42  BOOT_TIME
Apr    5    10:09:17  BOOT_TIME
Apr    8    09:47:02  BOOT_TIME
Apr    8    21:21:34  BOOT_TIME
Apr    9    09:34:50  BOOT_TIME
Apr    9    21:16:49  BOOT_TIME
0
02.05.2020, 10:20
4 ответа

Вы можете попробовать что-то подобное, используяsed:

$ sed -e :a -e 's:\([0-9][0-9]*\)/\1:\1:' -e ta file
rep1 rep2
g1001_INpfu_DN44908_c3_g1 17.85 19.95
g10042/1330/2846_INpfu_DN43979_c0_g3 34.07 29.19
g1077/1457/278_INpfu_PRJNA287145_DN42983_c0_g1 20.69 21.64
g100_INpfu_DN43143_c0_g1 52.36 33.64
g79_INpfu_DN45068_c4_g1 58.83 74.58

Чтобы обрабатывать частичные совпадения, такие как g512/12/xили g512/5120/x, не превращая их в g512/xи g5120/x, вы можете добавить привязки цифр, отличных от -, с обеих сторон:

sed -e :a -e 's:\([^0-9]\)\([0-9][0-9]*\)/\2\([^0-9]\):\1\2\3:' -e ta file

или чуть более читабельно с использованием расширенных регулярных выражений

sed -E -e :a -e 's:([^0-9])([0-9]+)/\2([^0-9]):\1\2\3:' -e ta file

напр. дано

$ cat file
    rep1 rep2
g1001_INpfu_DN44908_c3_g1 17.85 19.95
g10042/1330/2846_INpfu_DN43979_c0_g3 34.07 29.19
g1077/1457/278/278_INpfu_PRJNA287145_DN42983_c0_g1 20.69 21.64
g512/12_INpfu_DN43143_c0_g1 52.36 33.64
g100/100_INpfu_DN43143_c0_g1 52.36 33.64
g512/5120_INpfu_DN43143_c0_g1 52.36 33.64
g79/79/79/79_INpfu_DN45068_c4_g1 58.83 74.58

, затем

$ sed -E -e :a -e 's:([^0-9])([0-9]+)/\2([^0-9]):\1\2\3:' -e ta file
    rep1 rep2
g1001_INpfu_DN44908_c3_g1 17.85 19.95
g10042/1330/2846_INpfu_DN43979_c0_g3 34.07 29.19
g1077/1457/278_INpfu_PRJNA287145_DN42983_c0_g1 20.69 21.64
g512/12_INpfu_DN43143_c0_g1 52.36 33.64
g100_INpfu_DN43143_c0_g1 52.36 33.64
g512/5120_INpfu_DN43143_c0_g1 52.36 33.64
g79_INpfu_DN45068_c4_g1 58.83 74.58
0
28.04.2021, 23:16

Сperl:

perl -pe 's{^g(?:\d+/)*?(\d+)\K(?:/\1)+(?!\d)}{}' < your-file

Он строгий в том смысле, что удаляет первую последовательность повторяющихся чисел только в первой g/number/number[/number...]/numberчасти и только в том случае, если за этой частью не следует цифра.

С sedвы можете сделать то же самое с:

sed '
  \|^\(g\([[:digit:]]\{1,\}/\)*[[:digit:]]\{1,\}\).*| {
    h; # save a copy of original line
    s||\1:|; # remove all but the leading g/x/y/z
    s|\([g/]\)\([[:digit:]]\{1,\}\)\(/\2\)\{1,\}\([^[:digit:]]\)|\1\2\4|
    G; # append saved copy
    s|:\ng\([[:digit:]]\{1,\}/\)*[[:digit:]]\{1,\}||; # remove excess
  }' < your-file
-1
28.04.2021, 23:16

Наименьшее количество предположений:

  • разделить ввод на поля, разделенные _(, как указано в OP)
  • ожидайте, что числа на самом деле являются числами, поэтому разделение шаблона

    patsplit( $1, v, /[0-9]{1,}/, s )
    

    где v — массив значений, а s — массив разделителей. Извлечет все числа и разделители (, начальный gи каждый/)первого поля (перед первым _, как определено OP ).

Затем, чтобы удалить повторяющиеся числа (, которые могут быть не отсортированы )в результирующем массиве v, требуется двойной цикл (, если числа могут быть несортированными ).

Двойная петля может быть проблемой для большого числа чисел (нескольких тысяч ), так как худший случай n 2 . Чтобы улучшить этот худший случай до n *log (n ), нам нужно сначала отсортировать.

Этот awk-код делает это:

awk 'BEGIN{OFS=FS="_"}
     NF>1{
         n=patsplit($1,v,/[0-9]{1,}/,s);            # count of numbers.
         for(i=1;i<=n;i++){                         # for each initial field and
             for(j=n;j>i;j--){                      # for each next field
                 if(v[j]!="" && v[i]==v[j]){        # check if they are equal
                     v[j]="";s[j-1]="";             # and remove the number and
                                                    # the preceding separator.
                 }
             }
         }
         str=""                                     # with a clean variable str
         for(i=1;i<=n;i++){                         # for all available numbers
             str=str "" sprintf("%s%s",s[i-1],v[i]) # rebuild the value of $1
         }
         $1=str;
     }
42                          # print. No, it is not the answer to
                            # Life, the Universe and everything
' file
-1
28.04.2021, 23:16

Раздел замены заканчивается первым _Номера для замены разделены /Существует способ удалить все повторяющиеся числа (, независимо от того, являются ли они последовательными или нет ), например

  • последние 278 в 278/278
  • последние 278 в 278/1455/278
  • все 79 в 79/79/79/79 (все повторы, первый не повтор ).

С перлом:

perl -pe 's//\1\2/ while /(?<!\d)(\d+)(?!\d)([^_]*)\/\1(?!\d)/ ' file
s//\1\2/     # substitute the regex by the captures of \1 and \2.
while        # for as long as there is a match in the regex.
/.../        # regex
(?<!\d)      # start on a non digit.
(\d+)        # contains several digits (at least one) (first capture: \1).
(?!\d)       # and ends in a non digit.
([^_]*)      # capture the characters between the repetitions (\2)
             # but do not extend the match after the `_`
\/\1         # match a `/` and what was captured by `\1`
             # that is: the repetition.
(?!\d)/      # followed by a non-digit.

Например, в этом файле:

rep1 rep2
g1001_INpfu_DN44908_c3_g1 17.85 19.95
g10042/1330/2846_INpfu_DN43979_c0_g3 34.07 29.19
g1077/1457/278/278_INpfu_PRJNA287145_DN42983_c0_g1 20.69 21.64
g1077/1457/278/1455/278_INpfu_PRJNA287145_DN42983_c0_g1 20.69 21.64
g1077/1457/278/1457/1088/278/1433_INpfu_PRJNA287145_DN42983_c0_g1 20.69 21.64
g100/100_INpfu_DN43143_c0_g1 52.36 33.64
g100/100/100_INpfu_DN43143_c0_g1 52.36 33.64
g2100/100_INpfu_DN43143_c0_g1 52.36 33.64
g79/79/79/79_INpfu_DN45068_c4_g1 58.83 74.58
g79/82/79/96/79/79_INpfu_DN45068_c4_g1 58.83 74.58

Будет сгенерирован этот вывод:

rep1 rep2
g1001_INpfu_DN44908_c3_g1 17.85 19.95
g10042/1330/2846_INpfu_DN43979_c0_g3 34.07 29.19
g1077/1457/278_INpfu_PRJNA287145_DN42983_c0_g1 20.69 21.64
g1077/1457/278/1455_INpfu_PRJNA287145_DN42983_c0_g1 20.69 21.64
g1077/1457/278/1088/1433_INpfu_PRJNA287145_DN42983_c0_g1 20.69 21.64
g100_INpfu_DN43143_c0_g1 52.36 33.64
g100_INpfu_DN43143_c0_g1 52.36 33.64
g2100/100_INpfu_DN43143_c0_g1 52.36 33.64
g79_INpfu_DN45068_c4_g1 58.83 74.58
g79/82/96_INpfu_DN45068_c4_g1 58.83 74.58

Все повторы удалены.

Конечно, это также работает для исходного файла.

-1
28.04.2021, 23:16

Теги

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