라는 배열이 있다고 가정합니다 a
. 배열에는 2개의 항목이 있습니다 a[1]
. a[2]
따라서 각 요소에는 숫자 값이 포함됩니다. 두 값 모두 시작 번호는 비슷하지만 끝은 다릅니다. 비슷한 부분만 복사하고 나머지는 무시하겠습니다.
그래서예
$ 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
답변1
에서스택 오버플로:
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
정규식의 앞에 사용되어야 합니다.정규식을 사용하여 반복되는 문자열 찾기 이에 대한 비결은 잘 알려져 있으며 항상 다음과 같은 변형을 사용합니다.
(.*)\1
.*
모든 문자 집합과 일치하고()
나중에 참조할 수 있도록 그룹화합니다\1
. 따라서(.*)\1
그 자체가 뒤에 오는 문자 시퀀스입니다.
답변2
여기 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
: 새로 추가엘을 호출할 때마다 ineprint
에서 제공하는 스크립트를 실행합니다-e
.@A=split(//,$ARGV[0])
:$ARGV[0]
명령줄에 제공된 첫 번째 인수입니다. 이렇게 하면 분할되어 각 문자가 array 의 요소가 됩니다@A
.@B=split(//,$ARGV[1]);
: 위와 동일하지만 두 번째 인수와 배열에 대한 것입니다@B
.for $i (0..$#A)
: for 루프입니다. 이는$i
0으로 설정되고 배열의 요소 수 값을 가질 때까지 1씩 증가합니다@A
($#A
). 이는 , , ... ,$A[$i]
이기 때문에 배열의 모든 요소를 반복하는 간단한 방법입니다 .$A[0]
$A[1]
$A[$#A]
$A[$i] eq $B[$i] ? push @S,$A[$i] : last
: 이것은 C 스타일의 단축 표기법입니다. 일반적인 형식은foo ? bar : baz
"iffoo
is true, dobar
, else do 입니다baz
. 여기서 우리는 array의n
th(또는$i
th) 요소가@A
array의 해당 요소와 동일한 지 여부를 테스트하고 있습니다@B
. 그렇다면 우리는 세 번째 배열인 에 추가합니다@S
. 그렇지 않은 경우 를 사용하여 루프를 종료합니다last
.print @S
: 배열@S
, 공유 요소를 인쇄합니다.
두 가지 솔루션은 매우 유사합니다. 유일한 차이점은 로 @A=split(/\./,$ARGV[0])
분할하여 .
결과 배열에서 제거하고 그 사이 에 print join ".", @S
의 모든 요소를 인쇄한다는 것입니다 .@S
.
답변3
질문 아래의 설명에서 언급했듯이 다소 간단한 awk
해결책을 찾았습니다. 두 숫자를 연결하여 하나의 긴 문자열을 만들고 모든 점을 공백으로 바꾸고(awk에서 공백을 기본 필드 구분 기호로 사용할 수 있도록 허용) 파일+절반을 사용하여 문자열 비교 필드를 통과합니다.
기본 명령
printf ${a[1]}${a[2]} | awk '{gsub("\\."," "); half=NF/2}; { for ( x=1; x<=half; x++ ) { if ( $x==$(x + half) ) printf "."$x };}'
나는 이것을 gawk와 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에서 줄 바꿈으로 구분한 다음 awk 명령 끝에 다음과 같이 printf를 추가하세요.
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]
출력 제한
이제 kos의 의견은 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
같지 않은 첫 번째 숫자까지 비교
substr(string,X,Y)
Awk에는 첫 번째 문자(x)부터 끝 문자(Y)까지 문자열을 자르거나 "자르기"할 수 있는 매우 유용한 기능이 있습니다 . 이를 알고 있으므로 두 숫자를 한 문자열의 두 필드로 가져와 while 루프를 통해 실행해 보겠습니다. 더 이상 동일하지 않을 때까지 하위 문자열 길이(시작부터 끝까지)를 계속 늘릴 것입니다. 동일하지 않은 하위 문자열을 발견하면 종료하고 마지막으로 알려진 동일한 하위 문자열을 인쇄합니다.
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}'
이전에는 존재조차 몰랐던 substr 함수 사용을 제안한 terdon에게 특별히 감사드립니다.
답변4
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
.
변수에는 ( ) 로 분할된 입력 목록의 첫 번째 요소 부분이 포함됩니다a[0].split
. 마찬가지로second
list 의 두 번째 요소 부분도 포함됩니다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