과 **/*.ext
일치하는 모든 하위 디렉토리의 모든 파일로 확장된다는 것을 알고 *.ext
있지만 현재 디렉토리 에있는 모든 파일을 포함하는 유사한 확장은 무엇 입니까?
답변
이것은 Bash 4에서 작동합니다.
ls -l {,**/}*.ext
이중 별표 glob이 작동하려면 globstar
옵션을 설정해야합니다 (기본값 : on).
shopt -s globstar
에서 man bash
:
글롭 스타 설정하면 파일 이름 확장에 사용되는 ** 패턴이 연결됩니다. 텍스트는 파일 및 0 개 이상의 디렉토리와 일치하며 하위 디렉토리. 패턴 뒤에 /가 있으면 디렉터리와 하위 디렉터리가 일치합니다.
이제 globstar 처리에 버그가 있었는지 궁금합니다. 이제 단순히 사용하여 ls **/*.ext
올바른 결과를 얻고 있기 때문 입니다.
그럼에도 불구하고 kenorb가 VLC 저장소를 사용하여 수행 한 분석을 살펴본 결과 해당 분석과 바로 위의 대답에서 몇 가지 문제를 발견했습니다.
find
지정 -type f
에는 다른 파일 유형 (특히 디렉토리)이 포함되지 않고 ls
나열된 명령이 포함될 가능성이 있으므로 명령 의 출력에 대한 비교 는 유효 하지 않습니다 . 또한 나열된 명령 중 하나는 ls -1 {,**/}*.*
위의 내 것을 기반으로하는 것처럼 보이지만 하위 디렉터리에있는 파일에 대해 점이 포함 된 이름 만 출력합니다 . OP의 질문과 내 대답에는 특정 확장자를 가진 파일이 있기 때문에 점이 포함됩니다.
그러나 가장 중요한 것은 ls
globstar 패턴과 함께 명령을 사용하는 데 특별한 문제가 있다는 것입니다 **
. 패턴이 Bash에 의해 검사되는 트리의 모든 파일 이름 (및 디렉토리 이름)으로 확장되기 때문에 많은 중복이 발생합니다. 확장 후에 ls
명령은 각각 과 디렉토리 인 경우 내용을 나열 합니다 .
예:
현재 디렉토리에는 하위 디렉토리 A
와 그 내용이 있습니다.
A
└── AB
└── ABC
├── ABC1
├── ABC2
└── ABCD
└── ABCD1
해당 트리에서 **
“AA / AB A / AB / ABC A / AB / ABC / ABC1 A / AB / ABC / ABC2 A / AB / ABC / ABCD A / AB / ABC / ABCD / ABCD1″(7 개 항목)으로 확장됩니다. . 그렇게 echo **
하면 정확한 출력을 얻을 수 있으며 각 항목은 한 번 표시됩니다. 그러나 그렇게 ls **
하면 각 항목 의 목록이 출력 됩니다. 그래서 본질적 ls A
으로 ls A/AB
, 등 이 뒤 따르 므로 A/AB
두 번 표시됩니다. 또한 ls
각 하위 디렉토리의 출력을 별도로 설정합니다.
...
<blank line>
directory name:
content-item
content-item
따라서 using wc -l
은 모든 빈 줄과 디렉토리 이름 섹션 제목을 계산하여 훨씬 더 많이 계산합니다.
이것은 파싱ls
하지 말아야하는 또 다른 이유 입니다.
이 추가 분석의 결과로 다음과 같은 방식으로 파일 트리를 반복하는 것 외에는 어떤 상황에서도 globstar 패턴을 사용하지 않는 것이 좋습니다.
for entry in **
do
something "$entry"
done
최종 비교를 위해 내가 편리했던 Bash 소스 저장소를 사용하여 다음과 같이했습니다.
shopt -s globstar dotglob
diff <(echo ** | tr ' ' '\n') <(find . | sed 's|\./||' | sort)
0a1
> .
내가 사용하는 tr
어떤 이름은 공백을 포함하지 않기 때문에 여기에만 유효 줄 바꿈에 공간을 변경할 수 있습니다. 에서 출력의 각 줄 sed
에서 선행을 제거하는 데 사용 되었습니다 . 일반적으로 정렬되지 않았고 Bash의 glob 확장이 이미 정렬되어 있기 때문에 출력을 정렬했습니다. 당신이 볼 수 있듯이,의 유일한 출력은 현재 디렉토리이었다 에 의해 출력 . 내가 할 때 출력에는 거의 두 배의 라인이 있습니다../
find
find
diff
.
find
ls ** | wc -l
답변
그러면 현재 디렉토리와 ‘.ext’로 끝나는 하위 디렉토리의 모든 파일이 인쇄됩니다.
find . -name '*.ext' -print
답변
다음 **/*.*
을 사용 하여 모든 파일을 재귀 적으로 포함 할 수 있습니다 (활성화 🙂 shopt -s globstar
.
아래에서 다른 변형 및 작동 방식을 테스트하십시오.
샘플 VLC 저장소 폴더 에 3472 파일이있는 테스트 폴더 :
(총 당으로 계산 3472의 파일 : find . -type f | wc -l
)
ls -1 **/*.*
-3338 반환ls -1 {,**/}*.*
-3341을 반환합니다 ( Dennis가 제안한대로 ).ls -1 {,**/}*
-8265 반환ls -1 **/*
-숨겨진 파일을 제외하고 7817을 반환합니다 ( Dennis가 제안한대로 ).ls -1 **/{.[^.],}*
-7869를 반환합니다 ( Dennis가 제안한대로 ).ls -1 {,**/}.?*
-15855 반환ls -1 {,**/}.*
-20321 반환
따라서 모든 파일을 재귀 적으로 나열하는 가장 가까운 방법 **/*.*
은 gniourf-gniourf 주석 (파일에 적절한 확장자가 있다고 가정하거나 특정 확장자를 사용한다고 가정 )에 따른 첫 번째 예제 ( ) 라고 생각합니다. 두 번째 예제에서는 아래와 같이 중복 항목이 거의 없습니다. :
$ diff -u <(ls -1 {,**/}*.*) <(ls -1 **/*.*)
--- /dev/fd/63 2015-04-19 15:25:07.000000000 +0100
+++ /dev/fd/62 2015-04-19 15:25:07.000000000 +0100
@@ -1,6 +1,4 @@
COPYING.LIB
-COPYING.LIB
-Makefile.am
Makefile.am
@@ -45,7 +43,6 @@
compat/tdestroy.c
compat/vasprintf.c
configure.ac
-configure.ac
다른 하나는 더 많은 중복을 생성합니다.
숨겨진 파일을 포함하려면 다음을 사용하십시오. shopt -s dotglob
(으로 비활성화 shopt -u dotglob
). mv
또는 같은 명령에 영향을 미칠 rm
수 있고 실수로 잘못된 파일을 제거 할 수 있으므로 권장되지 않습니다 .
답변
$ find . -type f
현재 디렉토리에있는 모든 파일이 나열됩니다. 그런 다음 -exec를 사용하여 출력에서 다른 명령을 수행 할 수 있습니다.
$find . -type f -exec grep "foo" {} \;
그러면 문자열 “foo”에 대한 검색에서 각 파일을 grep합니다.
답변
중괄호 확장을 사용하여 현재 디렉토리도 포함하지 않는 이유는 무엇입니까?
./{*,**/*}.ext
중괄호 확장은 glob 확장 전에 발생하므로 이전 버전의 bash에서 원하는 작업을 효과적으로 수행 할 수 있으며 최신 버전에서 globstar를 사용하여 원숭이 작업을 방지 할 수 있습니다.
또한 bash ./
에서는 glob 패턴에 선행을 포함하는 것이 좋습니다 .