development

현재 디렉토리의 모든 파일을 재귀 적으로 확장하는 것은 무엇입니까?

big-blog 2020. 9. 14. 21:31
반응형

현재 디렉토리의 모든 파일을 재귀 적으로 확장하는 것은 무엇입니까?


**/*.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의 질문과 내 대답에는 특정 확장자를 가진 파일이 있기 때문에 점이 포함됩니다.

그러나 가장 중요한 것은 lsglobstar 패턴과 함께 명령을 사용하는 데 특별한 문제가 있다는 것입니다 **. 패턴이 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 해서는 안되는 또 다른 이유 입니다.

As a result of this further analysis, I recommend not using the globstar pattern in any circumstance other than iterating over a tree of files in this manner:

for entry in **
do
    something "$entry"
done

As a final comparison, I used a Bash source repository I had handy and did this:

shopt -s globstar dotglob
diff <(echo ** | tr ' ' '\n') <(find . | sed 's|\./||' | sort)
0a1
> .

I used tr to change spaces to newlines which is only valid here since no names include spaces. I used sed to remove the leading ./ from each line of output from find. I sorted the output of find since it is normally unsorted and Bash's expansion of globs is already sorted. As you can see, the only output from diff was the current directory . output by find. When I did ls ** | wc -l the output had almost twice as many lines.


This wil print all files in the current directory and its subdirectories which end in '.ext'.

find . -name '*.ext' -print

You can use: **/*.* to include all files recursively (enable by: shopt -s globstar).

Please find below testing of other variations and how they behave.


Testing folder with 3472 files in the sample VLC repository folder:

(Total files of 3472 counted as per: find . -type f | wc -l)

  • ls -1 **/*.* - returns 3338
  • ls -1 {,**/}*.* - returns 3341 (as proposed by Dennis)
  • ls -1 {,**/}* - returns 8265
  • ls -1 **/* - returns 7817, except hidden files (as proposed by Dennis)
  • ls -1 **/{.[^.],}* - returns 7869 (as proposed by Dennis)
  • ls -1 {,**/}.?* - returns 15855
  • ls -1 {,**/}.* - returns 20321

So I think the most closest method to list all files recursively is the first example (**/*.*) as per gniourf-gniourf comment (assuming the files have the proper extensions, or use the specific one), as the second example gives few more duplicates like below:

$ 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

and the other generate even further duplicates.


To include hidden files, use: shopt -s dotglob (disable by shopt -u dotglob). It's not recommended, because it can affect commands such as mv or rm and you can remove accidentally the wrong files.


$ find . -type f

That will list all of the files in the current directory. You can then do some other command on the output using -exec

$find . -type f -exec grep "foo" {} \;

That will grep each file from the find for the string "foo".


Why not just use brace expansion to include the current directory as well?

./{*,**/*}.ext

Brace expansion happens before glob expansion, so you can effectively do what you want with older versions of bash, and can forego monkeying with globstar in newer versions.

Also, it's considered good practice in bash to include the leading ./ in your glob patterns.

참고URL : https://stackoverflow.com/questions/1690809/what-expands-to-all-files-in-current-directory-recursively

반응형