Предположим, мне назвали массив 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
В 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
любая последовательность символов, сопровождаемых отдельно.
Используя 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)
Вот является 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
. Здесь, мы тестируем ли n
th (или $i
th, в этом случае) элемент массива @A
совпадает с соответствующим от массива @B
. Если это, мы добавляем его к третьему массиву, @S
. Если это не, мы выходим из цикла с last
. print @S
: распечатайте массив @S
, общие элементы.Эти два решения очень похожи, единственная разница - это @A=split(/\./,$ARGV[0])
разделит на .
, удаление их от полученного массива и print join ".", @S
распечатает все элементы @S
с a .
между ними.
Поскольку я упомянул в реве комментариев вопрос, я нашел несколько простое 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, которую я ранее не знал даже,
Можно определить немного 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