일치하지만 확장자가 있는 파일 나열

일치하지만 확장자가 있는 파일 나열

경로가 있는 파일이 주어지면

/foo/bar/a.b.c.d.x

최종 확장자가 /foo/bar/abcd*와 일치하는 모든 파일을 찾을 수 있기를 원합니다.

이것이 내가 지금까지 사용해온 것입니다.

findSiblingFiles () {
  local filePath="$1"
  find "$(dirname "$filePath")" -name "$(basename "${filePath%.*}").*"
}

이는 대부분의 경우 작동하지만 파일에 대괄호(예: "abc[helloworld].x")가 포함되어 있으면 작동하지 않습니다. 백슬래시가 대괄호를 벗어나면 작동하게 할 수 있지만 그렇게 하려면 함수에서 정규식을 사용하여 백슬래시를 추가해야 합니다. 그러면 혼란스러운 영역이 생기고 뭔가 빠진 것이 있는지 궁금합니다. 더 쉬운 방법 이것을하기 위해.

이상적으로는 다음 내용이 포함된 파일을 찾아야 합니다.어느파일 이름의 문자(대괄호, 중괄호, 괄호 등) 및 시간 효율성이 고려됩니다.

답변1

이 패턴과 일치하는 모든 파일을 보려면 /foo/bar/a.b.c.d.*다음을 사용하십시오.

printf '%s\n' /foo/bar/a.b.c.d.*

패턴과 일치하는 모든 파일을 보려면 /foo/bar/a.b.c.[helloworld].*(여기서 [hellowerld]텍스트는) 다음을 사용하십시오.

printf '%s\n' /foo/bar/a.b.c.'[helloworld]'.*

즉, 문자 그대로 표현해야 하는 패턴 부분을 참조합니다.

해당 문자열을 얻고 마지막 문자열을 제거하고 다음 으로 바꿀 때 얻은 패턴과 일치하는 해당 문자열 아래의 모든 파일을 a.b.c.[helloworld].x보려면/foo/bar.x.*

string='a.b.c.[helloworld].x'
printf '%s\n' /foo/bar/"${string%.*}".*

여기서 고려해야 할 유일한 것은 참조 변수 대체의 확장입니다.

bash쉘에서 이 작업을 재귀적으로 수행하고 숨겨진 이름을 포함시킨 다음 다음을 사용 하시겠습니까?

shopt -s globstar dotglob
string='a.b.c.[helloworld].x'
printf '%s\n' /foo/bar/**/"${string%.*}".*

귀하의 기능은 다음과 같이 작성될 수 있습니다(하위 디렉터리에서 검색할 필요 없음).

findSiblingFiles () {
    printf '%s\n' "${1%.*}".*
}

또는 패턴이 일치하지 않는 경우 아무것도 출력하지 않고 빈 줄도 출력하지 않으려면,

findSiblingFiles () (
    shopt -s nullglob
    set -- "${1%.*}".*
    [ "$#" -gt 0 ] && printf '%s\n' "$@"
)

첫 번째 인수의 "꼬리"만 수정하므로 주어진 파일 이름에 실제로 점이 있는지 확인하려는 경우가 아니면 디렉터리 경로에서 파일 이름을 분리할 필요가 없습니다. 아래 코드에서는 이렇게 합니다. .

findSiblingFiles () (
    shopt -s nullglob

    if [[ ${1##*/} != *.* ]]; then
        echo 'Filename has no suffix' >&2
        return 1
    fi

    set -- "${1%.*}".*

    [ "$#" -gt 0 ] && printf '%s\n' "$@"
)

시험:

$ findSiblingFiles ~myself/local/src/project/doc/document.txt
/home/myself/local/src/project/doc/document.man
/home/myself/local/src/project/doc/document.mdoc
/home/myself/local/src/project/doc/document.txt

답변2

그리고 zsh:

filesWithSameRootName() {
  set -o localoptions -o extendedglob
  local filepath=${1%%/#}
  print -rC1 -- $filepath:h/**/$filepath:r(|[^.]#)(ND)
}

$filepath:rcsh나 vim과 마찬가지로(또는 bash기록 확장에만 해당) return뿌리path, 즉 확장자가 없는 파일 경로입니다. For dir.d/file.foo.bar, 즉 for , 즉 dir.d/file.foo( for , 따라서 후행 s는 먼저 위에서 제거됩니다 ).dir.d/filedir.d/filedir.d/dir.d//

그래서 같은 파일을 찾으려면뿌리**/, 첨부된 선택적 파일을 (재귀적으로) 찾습니다 ..<zero-or-more-non-dots>

find( -name, , ...) -path의 모든 이름 일치 조건자는 -regex패턴을 인수(셸 와일드카드 또는 정규식)로 사용하므로 하위 문자열 일치를 위해서는 정규식 연산자를 이스케이프 처리해야 합니다. 또는 find -print0POSIX 구문을 사용하여 기본 문자열 비교를 수행하는 작업을 사용하여 출력을 사후 처리(또는 POSIXly: )할 수 있습니다 .find -exec printf '%s\0' {} +shperl

filesWithSameRootName() {
  find "$(dirname -- "$1")" -exec printf '%s\0' {} + |
    FILE="$1" perl -l -0ne '
      BEGIN{
        $root = $ENV{FILE};
        $root =~ s{.*/}{};
        $root =~ s{\.[^./]*\Z}{};
      }
      print if m{/\Q$root\E(\.[^.]*)?\Z}'
}

(glob로 정렬되지 않고 zsh디렉토리 이름이 개행 문자로 끝나지 않고 / -또는 !/ 로 시작하지 않는다고 가정하더라도 (... ))

관련 정보