Сохраните вывод в 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
Вы можете попробовать что-то подобное, используя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
С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
Наименьшее количество предположений:
_
(, как указано в 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
Раздел замены заканчивается первым _
Номера для замены разделены /
Существует способ удалить все повторяющиеся числа (, независимо от того, являются ли они последовательными или нет ), например
С перлом:
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
Все повторы удалены.
Конечно, это также работает для исходного файла.