바로 이전 경로보다 더 깊은 텍스트 파일의 경로를 필터링합니다.

바로 이전 경로보다 더 깊은 텍스트 파일의 경로를 필터링합니다.

정렬된 경로 목록이 포함된 텍스트 파일이 있는 경우 해당 상위 경로(직접 여부와 상관없이)도 목록에 있기 때문에 중복되는 모든 경로를 제거하려면 어떻게 해야 합니까?

예를 들어:

/aaa/bbb
/aaa/bbb/ccc
/ddd/eee
/fff/ggg
/fff/ggg/hhh/iii
/jjj/kkk/lll/mmm
/jjj/kkk/lll/mmm/nnn

다음과 같이 줄여야 합니다.

/aaa/bbb
/ddd/eee
/fff/ggg
/jjj/kkk/lll/mmm

awk에서 하위 문자열을 사용해 보았지만 상위 경로가 매번 동일한 수준에 있을 것이라고 보장할 수 없으므로 제대로 작동할 수 없습니다.

답변1

나는 이것이 가능해야 한다고 생각한다. 더 많은 사례를 추가하려면 입력 파일을 수정하세요.

$ cat ip.txt 
/aaa/bbb
/aaa/bbbd
/aaa/bbb/ccc
/ddd/eee
/fff/ggg
/fff/ggg/hhh/iii
/jjj/kkk/lll/mmm
/jjj/kkk/lll/mmm/nnn
/jjj/kkk/xyz

사용awk

$ awk '{for (i in paths){if (index($0,i"/")==1) next} print; paths[$0]}' ip.txt 
/aaa/bbb
/aaa/bbbd
/ddd/eee
/fff/ggg
/jjj/kkk/lll/mmm
/jjj/kkk/xyz
  • paths[$0]입력 행에 의해 키가 지정된 참조입니다.
  • for (i in paths)각 행은 저장된 모든 키와 비교됩니다.
  • if (index($0,i"/")==1) next/줄 시작 부분에 추가된 저장된 키와 일치하는 경우 입력 줄을 건너뜁니다.
    • //aaa/bbbd매칭을 피하기 위해 사용됨/aaa/bbb

답변2

그리고 강제 sed솔루션은 다음과 같습니다.

sed '1s/^/#/;x;G;\_#\([^#]*\)#.*\n\1/_s/\n.*//;s/\n\(.*\)/\1#/;h;$! d;x;s/^#//;s/#$//;y/#/\n/'

이 스크립트는 예약된 공간에서 경로를 수집합니다. 각각의 새 라인에 대해 예약된 공간이 패턴 공간에 추가되어 발생 여부를 확인합니다.

이 솔루션에서는 #해당 문자가 파일에 사용되지 않는다고 가정합니다. 그렇지 않으면 다른 문자를 사용하거나, GNU를 사용하는 경우 sed게시물 하단에 있는 짧은 버전을 사용하세요.

상해:

1s/^/#/

이식성을 위해 #예약된 공간에서 경로를 구분하는 데 문자가 사용됩니다. 첫 번째 줄의 경우 처음부터 시작해야 합니다.#

x;G

By exchanging the spaces and appending the hold space, we have the list of already occured buffers first, then the new path.

\_#\([^#]*\)#.*\n\1/_s/\n.*//

주소가 일치 하면 \_..._새 경로는 이전 경로의 하위 경로이므로 삭제됩니다.

s/\n\(.*\)/\1#/

여전히 공백에 줄 바꿈이 있으므로 경로가 새 경로이므로 목록에 추가합니다.

h;$! d

마지막 행이 아닌 경우 새 목록을 예약된 공간에 저장하고 다시 시작하세요.

x;s/^#//;s/#$//;y/#/\n/

마지막 줄의 시작과 끝 내용을 삭제하고 #다른 내용을 줄바꿈으로 바꿉니다.#

GNU의 대안sed

sed순서가 복원되어도 괜찮다면 GNU 확장을 사용하여 이 작업을 더 간단하게 수행할 수 있습니다.

sed 'G;\_^\([^\n]*\)/.*\n\1\n_s/[^\n]*\n//;h;$! d;x;s/^\n//;s/\n$//'

위와 같이 설명했지만 #.

답변3

이 같은:

$ awk '{sub(/\/$/, "")} 
    NR != 1 && substr($0, 0, length(prev)) == prev {next}; 
    {print; prev = $0"/" }  ' paths 

첫 번째( NR != 1)를 제외한 모든 줄에서 해당 줄의 접두어를 저장된 줄 prev( 길이만큼의 문자 prev)과 비교합니다. 일치하면 next해당 행으로 이동합니다. 그렇지 않으면 print출력하고 행을 에 저장합니다 prev.

파일이 C 로케일로 정렬되어 있다고 가정하면(예: /문자 앞), 또는 디렉토리 트리 탐색을 통해 생성된 경우 이전에 저장된 행에 대해 테스트하는 것으로 충분합니다. 파일이 다른 로케일로 정렬된 경우 /정렬에 영향을 주지 않아 , , 와 같은 정렬이 발생할 수 /aaa/bbb있습니다 /aaaccc. /aaa/ddd파일이 전혀 정렬되지 않으면 하위 디렉터리가 상위 디렉터리 앞에 나타날 수 있으며 문제가 어려워집니다.

첫 번째는 sub(...)줄에서 후행 슬래시(있는 경우)를 제거합니다. 줄을 저장할 때 파일 이름의 일부가 일치하지 않도록 후행 슬래시를 추가합니다.

답변4

perl -lne '$l=$_; grep $l =~ m|^\Q$_/|, @A or print, push @A, $_'
  • 특정 행에 제공된 다양한 경로를 모두 누적했는데 array @A해당 행에 이미 저장된 경로와 일치하지 않습니다.
  • grep은 m|^\Q$_/|배열 요소를 참조하고 일치하는 항목을 찾습니다.

sed -ne '
   H                              # append current line into hold space
   g                              # pattern space = hold space \n current line
   y/\n_/_\n/                     # change coordinate system
   \|_\([^_]*\)_\(.*_\)\{0,1\}\1/|s/\(.*\)_.*/\1/ # match yes, strip current line
   y/\n_/_\n/                     # revert coordinate system
   h                              # update hold space
   $s/.//p                        # answer
'

산출

/aaa/bbb
/ddd/eee
/fff/ggg
/jjj/kkk/lll/mmm

관련 정보