경로가 있는 파일이 주어지면
/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:r
csh나 vim과 마찬가지로(또는 bash
기록 확장에만 해당) return뿌리path, 즉 확장자가 없는 파일 경로입니다. For dir.d/file.foo.bar
, 즉 for , 즉 dir.d/file.foo
( for , 따라서 후행 s는 먼저 위에서 제거됩니다 ).dir.d/file
dir.d/file
dir.d/
dir.d/
/
그래서 같은 파일을 찾으려면뿌리**/
, 첨부된 선택적 파일을 (재귀적으로) 찾습니다 ..<zero-or-more-non-dots>
find
( -name
, , ...) -path
의 모든 이름 일치 조건자는 -regex
패턴을 인수(셸 와일드카드 또는 정규식)로 사용하므로 하위 문자열 일치를 위해서는 정규식 연산자를 이스케이프 처리해야 합니다. 또는 find -print0
POSIX 구문을 사용하여 기본 문자열 비교를 수행하는 작업을 사용하여 출력을 사후 처리(또는 POSIXly: )할 수 있습니다 .find -exec printf '%s\0' {} +
sh
perl
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
디렉토리 이름이 개행 문자로 끝나지 않고 / -
또는 !
/ 로 시작하지 않는다고 가정하더라도 (
... )
)