재귀 적으로 특정 확장자를 가진 파일을 찾습니다


437

내 bash (Latest Ubuntu LTS Release)를 사용하여 디렉토리 및 하위 디렉토리에서 특정 확장자를 가진 모든 파일을 찾으려고합니다.

다음은 스크립트 파일로 작성된 것입니다.

#!/bin/bash

directory="/home/flip/Desktop"
suffix="in"

browsefolders ()
  for i in "$1"/*; 
  do
    echo "dir :$directory"
    echo "filename: $i"
    #   echo ${i#*.}
    extension=`echo "$i" | cut -d'.' -f2`
    echo "Erweiterung $extension"
    if     [ -f "$i" ]; then        

        if [ $extension == $suffix ]; then
            echo "$i ends with $in"

        else
            echo "$i does NOT end with $in"
        fi
    elif [ -d "$i" ]; then  
    browsefolders "$i"
    fi
  done
}
browsefolders  "$directory"

불행히도 터미널 에서이 스크립트를 시작하면 다음과 같이 말합니다.

[: 29: in: unexpected operator

( $extension대신 'in')

여기서 무슨 일이 일어나고 있습니까, 오류는 어디에 있습니까? 그러나이 중괄호


2
오류는 누락 된 '{'
shrewmouse

답변:


750
find $directory -type f -name "*.in"

전체보다 약간 짧습니다 (파일 이름 및 디렉토리 이름의 공백을 처리하는 것이 안전합니다).

.이름에 이름 이없는 항목이 $extension비어 있으면 스크립트가 실패했을 수 있습니다 .


16
예, find기본적으로 재귀입니다. 원하는 경우 깊이를 제한 할 수 있습니다 (설명서 페이지 참조).
Mat

1
찾은 모든 파일을 인수로 jar 파일에 전달하고 싶습니다. 이 작업을 어떻게 수행 할 수 있습니까?
플립

8
@ 플립 : 그것은 다른 질문입니다. 수행하려는 작업과 지금까지 시도한 작업을 자세히 설명하는 새로운 질문을 게시하십시오.
Mat

작은 수정 : 큰 따옴표는 쉘 확장을 막지 않기 때문에 "* .in"대신 '* .in'또는 \ *. in을 사용하십시오. 즉, 현재 디렉토리에 확장자가 .in 인 파일이 있으면 스크립트가 제대로 작동하지 않습니다.
Shnatsel

4
@ Shnatsel : 큰 따옴표는 쉘 확장을 방지합니다. 사용해보십시오.
Mat

188
find {directory} -type f -name '*.extension'

예 :csv 현재 디렉토리 및 해당 서브 디렉토리에서 모든 파일 을 찾으려면 다음 을 사용하십시오.

find . -type f -name '*.csv'

60

내가 사용하는 구문은 @Matt가 제안한 것과 약간 다릅니다.

find $directory -type f -name \*.in

(키 스트로크가 적습니다).


1
현재 디렉토리에 확장자가 .in 인 파일이 있으면 Matt의 스크립트도 작동하지 않지만 여전히 작동합니다. 참조 stackoverflow.com/questions/5927369/...
Shnatsel

4
@Shnatsel이 의견 (따라서 당신의 의견)은 명백합니다.
gniourf_gniourf 12

1
@gniourf_gniourf 당신은 당신의 진술에 대한 참조를 제공해야한다. 그러나 실제로 당신이 맞습니다 : gnu.org/software/bash/manual/html_node/Double-Quotes.html
Murmel

@ user1885518 : 스크립트가 작동하지 않는다고 주장하는 사람이되어야한다고 생각합니다. 스크립트가 실패하는 경우 몇 가지 예를 제공해야합니다. 그것은 스크립트가 깨진 곳에 주석을 남길 때 수행하는 것입니다. 공백, 줄 바꿈, 글로브 등을 포함하는 따옴표와 파일 이름에 관한 것이며, 왜 깨진 지 구체적으로 설명합니다.
gniourf_gniourf

2
토론에서 참조를 제공하는 것은 항상 좋은 방법이며 누가 처음인지에 달려 있지 않습니다. 그는해야합니다.
Murmel

14

사용하지 않고 find:

du -a $directory | awk '{print $2}' | grep '\.in$'

3
grep여기에 정말 필요가 없습니다. awk정규 표현식을 가지며 출력을 패턴과 일치하는 값으로 제한 할 수 있습니다.
Kenster

이 방법은 100 테라 바이트를 처리 할 때 매우 유용합니다. 찾기 명령을 처리하는 데 너무 많은 시간이 걸립니다. 이것은 즉시 시작됩니다.
Protonova

1
awk|grep안티 패턴입니다. awk가 grepping을하게하십시오.
Jens

10
  1. 있다 {빠진 후에는browsefolders ()
  2. 모든 $in해야$suffix
  3. 라인은 cut의 중간 부분 만 표시합니다 front.middle.extension. 쉘 매뉴얼 ${varname%%pattern}과 친구들을 읽으십시오 .

쉘 스크립팅의 연습으로 이것을 수행한다고 가정합니다. 그렇지 않으면 find이미 제안 된 솔루션이 갈 길입니다.

스크립트를 실행하지 않고 적절한 쉘 구문을 확인하려면을 사용하십시오 sh -n scriptname.



7

find여기서 명령을 사용하는 것이 유용 할 수 있지만 셸 자체는 타사 도구없이이 요구 사항을 충족하는 옵션을 제공합니다. bash쉘은 순환 경로에서 파일 이름을 얻을 수 있습니다 사용하여 확장 글로브 지원 옵션을 제공합니다 당신이 원하는 확장과 일치합니다.

확장 옵션은 다음과 같은 옵션을 extglob사용하여 설정해야 shopt합니다. 옵션은 지원으로 활성화 -s되고 he -u플래그로 비활성화됩니다 . 또한 몇 가지 옵션을 더 사용할 수 있습니다. 즉 nullglob, 일치하지 않는 glob가 완전히 쓸어 버리고 0 단어로 대체됩니다. 그리고 globstar그것은 모든 디렉토리를 통해 재귀를 허용합니다

shopt -s extglob nullglob globstar

이제 당신이해야 할 일은 glob 표현을 형성하여 아래와 같이 할 수있는 특정 확장자의 파일을 포함시키는 것입니다. 올바르게 인용하고 확장하면 특수 문자가있는 파일 이름은 그대로 유지되고 셸의 단어 분리로 인해 끊어지지 않기 때문에 배열을 사용하여 glob 결과를 채 웁니다.

예를 들어 *.csv재귀 경로의 모든 파일 을 나열하려면

fileList=(**/*.csv)

옵션 **은 하위 폴더를 통해 되풀이되고 *.csv언급 된 확장명 파일을 포함하도록 확장됩니다. 이제 실제 파일을 인쇄하려면 다음을 수행하십시오.

printf '%s\n' "${fileList[@]}"

쉘 스크립트에서 배열을 사용하고 적절한 인용 확장을 사용하는 것이 올바른 방법이지만 대화식으로 사용하려면 다음 ls과 같이 glob 표현식을 사용 하면됩니다.

ls -1 -- **/*.csv

이것은 여러 파일과 일치하도록 확장 될 수 있습니다. 즉, 여러 확장자로 끝나는 파일 (예 : find명령에 여러 플래그를 추가하는 것과 유사 ). 예를 들어 모든 재귀 이미지 파일을받을 필요의 경우를 생각해 확장 즉 *.gif, *.png그리고 *.jpg모든 당신은 필요

ls -1 -- **/+(*.jpg|*.gif|*.png)

이것은 부정적 결과를 갖도록 확장 될 수있다. 동일한 구문으로 glob의 결과를 사용하여 특정 유형의 파일을 제외 할 수 있습니다. 위의 확장자를 가진 파일 이름을 제외하고 싶다고 가정하면 할 수 있습니다

excludeResults=()
excludeResults=(**/!(*.jpg|*.gif|*.png))
printf '%s\n' "${excludeResults[@]}"

이 구문 !()은 내부에 나열된 파일 확장자를 포함하지 않는 부정 연산 |이며, 확장 정규식 라이브러리에서 globs의 OR 일치를 수행하는 데 사용되는 것과 같은 대체 연산자입니다.

이러한 확장 글로브 지원은 POSIX bourne 쉘에서 사용할 수 없으며 최신 버전에만 적용됩니다 bash. 따라서 POSIX 및 bash셸에서 실행되는 스크립트의 이식성을 고려하고 있다면 이 옵션이 적합하지 않습니다.


6

pom.xml현재 디렉토리에서 모든 파일 을 찾아서 인쇄하려면 다음을 사용하십시오.

find . -name 'pom.xml' -print


0
for file in "${LOCATION_VAR}"/*.zip
do
  echo "$file"
done 

1
이 코드는 질문에 대답 할 수 있지만,이 코드가 질문에 응답하는 이유 및 / 또는 방법에 대한 추가 컨텍스트를 제공하면 장기적인 가치가 향상됩니다.
rollstuhlfahrer
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.