Сравните 2 цифры и скопируйте только подобную часть sed/grep/awk

Предположим, мне назвали массив a. В массиве существует 2 записи a[1] и a[2].So каждый элемент содержит значение цифры. Оба этих значения имеют подобные стартовые числа однако, у них есть различные окончания. Я должен скопировать подобную часть и проигнорировать остальных.

Таким образом, как пример

$ echo ${a[1]}
.1.3.6.1.4.1.232.13600256

$ echo ${a[2]}
.1.3.6.1.4.1.232.13600276

Мне нужна некоторая команда, чтобы сравнить эти элементы и затем скопировать только подобную часть до первого не поле соответствия. т.е., в этом примере

ВЫВОД

similar part is .1.3.6.1.4.1.232

Другой пример

$ echo ${a[1]}
.1.3.6.1.4.1.759.2344.454545

$ echo ${a[2]}
.1.3.6.1.4.1.759.3234.454545

ВЫВОД для этого примера

similar part is .1.3.6.1.4.1.759
5
задан 22 June 2015 в 13:16

5 ответов

От переполнения стека:

В sed, принимая строки не содержат символов новой строки:

string1="test toast"
string2="test test"
printf "%s\n%s\n" "$string1" "$string2" | sed -e 'N;s/^\(.*\).*\n\1.*$/\1/'

Это предполагает, что сами строки не содержат новые строки.

Поэтому можно сделать:

printf "%s\n" "${a[1]}" "${a[2]}" | sed -r 'N;s/^(.*)(\..*)?\n\1.*$/\1/'

(\..*) должен устранить запаздывание . от общего раздела.


Решение включает две части:

  • Получение sed работать через две строки. Это сделано с помощью N, и может избежаться, если символ, как гарантируют, будет не во входе. Например, потому что пробелы не присутствуют в элементах, как дали, мы можем вместо этого использовать:

    printf "%s " "${a[1]}" "${a[2]}" | sed -r 's/^(.*)(\..*)? \1.*$/\1/'
    

    По существу символ или строка, разделяющая эти два элемента в выводе, должны использоваться после %s в printf форматирование строки, и прежде \1 в регулярном выражении.

  • Нахождение повторяющейся строки с помощью regex. Прием для этого известен, и всегда является изменением:

    (.*)\1
    

    .* соответствия любой набор символов, и () группирует их для дальнейшего использования, \1. Таким образом (.*)\1 любая последовательность символов, сопровождаемых отдельно.

7
ответ дан 23 November 2019 в 08:40

Используя awk (gawk):

awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" 

Или более читаемый:

awk -F. '{
    printf "%s","similar part is "
  }
  {
    for(i=1;i<=NF;i++) {
      first[i-1]=$i
    }

    getline;

    for(i=1;i<=NF;i++) {
      second[i-1]=$i
    }

    for(i=0;i<length(first);i++) {
      if(first[i] == second[i]) {
        result=result first[i]"."
      }
    }
    printf "%s",substr($result,0,length(result)-1)"\n"
}'
<час>

Пример

$ a=".1.3.6.1.4.1.759.2344.454545"
$ b=".1.3.6.1.4.1.759.3234.433226"

$ awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" <час> 

ОБНОВЛЕНИЕ В комментариях, OP хочет соответствовать только до первого несоответствия:

awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."} else {i=length(first)}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" 

Пример

$ a=".1.3.6.1.4.1.232.13600256.2"
$ b=".1.3.6.1.4.1.232.13600276.2"
$ awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."} else {i=length(first)}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" <час> 

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b" similar part is .1.3.6.1.4.1.232
<час>

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b"

Пример

$ a=".1.3.6.1.4.1.232.13600256.2"
$ b=".1.3.6.1.4.1.232.13600276.2"
$ awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."} else {i=length(first)}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" <час> 

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b" similar part is .1.3.6.1.4.1.232
<час>

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b" similar part is .1.3.6.1.4.1.759
<час>

ОБНОВЛЕНИЕ В комментариях, OP хочет соответствовать только до первого несоответствия:

awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."} else {i=length(first)}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" 

Пример

$ a=".1.3.6.1.4.1.232.13600256.2"
$ b=".1.3.6.1.4.1.232.13600276.2"
$ awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."} else {i=length(first)}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" <час> 

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b" similar part is .1.3.6.1.4.1.232
<час>

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b"

Пример

$ a=".1.3.6.1.4.1.232.13600256.2"
$ b=".1.3.6.1.4.1.232.13600276.2"
$ awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."} else {i=length(first)}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" <час> 

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b" similar part is .1.3.6.1.4.1.232
<час>

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b"

Или более читаемый:

awk -F. '{
    printf "%s","similar part is "
  }
  {
    for(i=1;i<=NF;i++) {
      first[i-1]=$i
    }

    getline;

    for(i=1;i<=NF;i++) {
      second[i-1]=$i
    }

    for(i=0;i<length(first);i++) {
      if(first[i] == second[i]) {
        result=result first[i]"."
      }
    }
    printf "%s",substr($result,0,length(result)-1)"\n"
}'
<час>

Пример

$ a=".1.3.6.1.4.1.759.2344.454545"
$ b=".1.3.6.1.4.1.759.3234.433226"

$ awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" <час> 

ОБНОВЛЕНИЕ В комментариях, OP хочет соответствовать только до первого несоответствия:

awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."} else {i=length(first)}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" 

Пример

$ a=".1.3.6.1.4.1.232.13600256.2"
$ b=".1.3.6.1.4.1.232.13600276.2"
$ awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."} else {i=length(first)}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" <час> 

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b" similar part is .1.3.6.1.4.1.232
<час>

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b"

Пример

$ a=".1.3.6.1.4.1.232.13600256.2"
$ b=".1.3.6.1.4.1.232.13600276.2"
$ awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."} else {i=length(first)}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" <час> 

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b" similar part is .1.3.6.1.4.1.232
<час>

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b" similar part is .1.3.6.1.4.1.759
<час>

ОБНОВЛЕНИЕ В комментариях, OP хочет соответствовать только до первого несоответствия:

awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."} else {i=length(first)}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" 

Пример

$ a=".1.3.6.1.4.1.232.13600256.2"
$ b=".1.3.6.1.4.1.232.13600276.2"
$ awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."} else {i=length(first)}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" <час> 

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b" similar part is .1.3.6.1.4.1.232
<час>

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b"

Пример

$ a=".1.3.6.1.4.1.232.13600256.2"
$ b=".1.3.6.1.4.1.232.13600276.2"
$ awk -F. '{printf "%s","similar part is "} {for(i=1;i<=NF;i++) {first[i-1]=$i} getline; for(i=1;i<=NF;i++) {second[i-1]=$i} for(i=0;i<length(first);i++) {if(first[i] == second[i]) {result=result first[i]"."} else {i=length(first)}} printf "%s",substr($result,0,length(result)-1)"\n"}' <<< "$a" <час> 

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

\n'"$b" similar part is .1.3.6.1.4.1.232
<час>

Протестированный с GNU Awk 4.1.1, API: 1.1 (GNU 3.1.2-p11 MPFR, MP GNU 6.0.0)

3
ответ дан 23 November 2019 в 08:40

Вот является Perl путем. Идея состоит в том, чтобы разделить обе входных строки на отдельные массивы и выполнить итерации по массивам, сохранив любые записи, которые идентичны в обоих:

perl -le '@A=split(//,$ARGV[0]);@B=split(//,$ARGV[1]); 
          for $i (0..$#A){$A[$i] eq $B[$i] ? push @S,$A[$i] : last} 
          print @S' "${a[0]}" "${a[1]}"
.1.3.6.1.4.1.759.

Это, однако, включает запаздывание .. Ваш вывод не делает (несмотря на то, что это было тем же в обеих переменных), поэтому если Вы хотите удалить его, используйте это вместо этого:

$ perl -le '@A=split(/\./,$ARGV[0]);@B=split(/\./,$ARGV[1]); 
            for $i (0..$#A){$A[$i] eq $B[$i] ? push @S,$A[$i] : last} 
            print join ".",@S' "${a[0]}" "${a[1]}"
.1.3.6.1.4.1.759

Объяснение

  • -le : добавьте новую строку к каждому вызову print и запущенный скрипт, данный -e.
  • @A=split(//,$ARGV[0]) : $ARGV[0] первый аргумент, данный на командной строке. Это разделит его, делая каждый символ элементом в массиве @A.
  • @B=split(//,$ARGV[1]); : то же как выше, но для 2-го аргумента и массива @B.
  • for $i (0..$#A) : для цикла. Это устанавливает $i к 0 и инкременты это одним, пока это не имеет значение числа элементов в массиве @A ($#A). Это - простой способ выполнить итерации по всем элементам в массиве с тех пор $A[$i] будет $A[0], $A[1], ... , $A[$#A].
  • $A[$i] eq $B[$i] ? push @S,$A[$i] : last : это - нотация стенографии C-стиля. Общий формат foo ? bar : baz и означает "если foo верно, сделать bar, еще сделайте baz. Здесь, мы тестируем ли nth (или $ith, в этом случае) элемент массива @A совпадает с соответствующим от массива @B. Если это, мы добавляем его к третьему массиву, @S. Если это не, мы выходим из цикла с last.
  • print @S : распечатайте массив @S, общие элементы.

Эти два решения очень похожи, единственная разница - это @A=split(/\./,$ARGV[0]) разделит на ., удаление их от полученного массива и print join ".", @S распечатает все элементы @S с a . между ними.

4
ответ дан 23 November 2019 в 08:40

Поскольку я упомянул в реве комментариев вопрос, я нашел несколько простое awk решение: свяжите два numberals, чтобы создать одну длинную строку, заменить все точки пространством (чтобы предоставить пространство использования как разделителя полей по умолчанию в awk) и пройти строковое поле сравнения с file+half.

Основная команда

printf ${a[1]}${a[2]} | awk '{gsub("\\."," "); half=NF/2}; { for ( x=1; x<=half; x++ ) { if ( $x==$(x + half) ) printf "."$x };}'

Я протестировал это с простофилей и mawk, работали в обоих.

Здесь производится с первым примером (.1.3.6.1.4.1.232.13600256 и.1.3.6.1.4.1.232.13600276):

$ printf ${a[1]}${a[2]} | awk '{gsub("\\."," "); half=NF/2}; { for ( x=1; x<=half; x++ ) { if ( $x==$(x + half) ) printf "."$x };}'
.1.3.6.1.4.1.232

Несколько сравнений

Если Вы хотите сравнить несколько строк одновременно, связать их вместе и отдельный с новой строкой в printf, то добавьте printf в конце команды awk как так:

printf "${a[1]}${a[2]}\n${a[3]}${a[4]}" | awk '{gsub("\\."," "); half=NF/2}; { for ( x=1; x<=half; x++ ) { if ( $x==$(x + half) ) printf "."$x }; printf "\n"}'

Вывод:

$ printf "${a[1]}${a[2]}\n${a[3]}${a[4]}" | awk '{gsub("\\."," "); half=NF/2}; { for ( x=1; x<=half; x++ ) { if ( $x==$(x + half) ) printf "."$x }; printf "\n"}'
.1.3.6.1.4.1.232 # same for a[1] and a[2]
.1.3.6.1.4.1.759 # same for a[3] and a[4]

Ограничение вывода

Теперь, комментарий Коса соответственно заметил, что OP хочет, чтобы были отображены только 7 чисел. С этой целью можно добавить канал к cut -d'.' -f1-8 команда. Как так:

printf "${a[5]}${a[6]}" | mawk '{gsub("\\."," "); half=NF/2}; { for ( x=1; x<=half; x++ ) { if ( $x==$(x + half) ) printf "."$x }; printf "\n"}' | cut -d'.' -f1-8

Вот демонстрационный вывод от моего терминала:

$ a[5]=.1.3.6.1.4.1.232.13600256.885


$ a[6]=.1.3.6.1.4.1.232.13600256.885


$ printf "${a[5]}${a[6]}" | mawk '{gsub("\\."," "); half=NF/2}; { for ( x=1; x<=half; x++ ) { if ( $x==$(x + half) ) printf "."$x }; printf "\n"}' | cut -d'.' -f1-8
.1.3.6.1.4.1.232.13600256.885


 half) ) printf "."$x }; printf "\n"}' | cut -d'.' -f1-8                      <
.1.3.6.1.4.1.232

Упрощение еще больше

Снова, все может быть помещено в awk сценарий

#!/usr/bin/awk -f

{
 gsub("\\."," "); 
 half=NF/2
}; 

{ 
 for ( x=1; x<=half; x++ ) { 
    if ( $x==$(x + half) ) printf "."$x 
  }; 
  printf "\n"
}

Образец выполняется:

$ printf "${a[5]}${a[6]}" | num-comp.awk | cut -d'.' -f1-8                     
.1.3.6.1.4.1.232

Сравнение до первого не-равного-количества

Awk имеет очень полезную функцию substr(string,X,Y) который позволяет сокращать или "обрезать" строку от первого символа (x) к окончанию (Y). Так знание, что, давайте возьмем эти два числа в качестве двух полей одной строки и выполним их через цикл с условием продолжения. Мы собираемся продолжать увеличиваться, длина подстроки (запустите к окончанию), пока они больше не равны. После того как мы встречаемся с неравными подстроками, мы выходим и печатаем последнюю известную равную подстроку.

echo ".1.3.6.1.4.1.232.13600256\t.1.3.6.1.4.1.232.13600276" | awk 'BEGIN{i=1}{ while(substr($1,1,i)==substr($2,1,i)){var=substr($1,1,i);i++};} END{print var}'

Существовала особая благодарность terdon для предложения использования функции substr, которую я ранее не знал даже,

3
ответ дан 23 November 2019 в 08:40

Можно определить немного python функция, которая может сделать задание:

#!/usr/bin/env python2
import itertools
def common_portion(a):
    first = a[0].split('.')
    second = a[1].split('.')
    result = []
    for (i, j) in itertools.izip(first, second):
        if i == j:
            result.append(i)
        else:
            break
    return 'Similar part is ' + '.'.join(result)
  • Мы должны предоставить список, содержащий строки, которые мы хотим проверить, как введено к функции

  • first переменная будет содержать части первого элемента входного списка splitted на . (a[0].split). Так же second будет содержать части второго элемента списка a.

  • Затем мы выполнили итерации first и second и проверьте равенство каждого элемента с его тем же индексируемым дубликатом, если они - то же затем, один из них сохраняется в отдельном списке result. Каждый раз, когда мы встретились с первым различием, мы убежали из цикла.

  • Наконец мы распечатали наш желаемый результат с присоединением к полям с .s ('.'.join(result))

Тест:

print common_portion(['.1.3.6.1.4.1.232.13600256', '.1.3.6.1.4.1.232.13600276'])

Similar part is .1.3.6.1.4.1.232


print common_portion(['.1.3.6.1.4.1.759.2344.454545', '.1.3.6.1.4.1.759.3234.454545'])

Similar part is .1.3.6.1.4.1.759
1
ответ дан 23 November 2019 в 08:40

Другие вопросы по тегам:

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