특정 확장자를 가진 모든 파일을 반복합니다.


109
for i in $(ls);do
    if [ $i = '*.java' ];then
        echo "I do something with the file $i"
    fi
done

현재 폴더의 각 파일을 반복하고 특정 확장자와 일치하는지 확인하고 싶습니다. 위의 코드가 작동하지 않습니다. 이유를 아십니까?


4
어때 for i in $(ls *.java); do echo "do something with file $i"; done?
연설자

if 문을 고칠 방법이 없습니까?
AR89

1
$i리터럴 문자열 "* .java"와 비교 하고 있습니다. 여기서 패턴 확장은 수행되지 않습니다.
chepner

if 문을있는 그대로 수정하려면 if [[ $i == *.java ]]; then..을 사용 하십시오 (이중 [[]] s 및 인용되지 않은 * .java에주의하십시오).
그 다른 사람

2
구문 분석하지 마십시오ls - chepner의 대답 @ 동의
글렌 잭맨

답변:


201

멋진 트릭이 필요하지 않습니다.

for i in *.java; do
    [ -f "$i" ] || break
    ...
done

가드는 일치하는 파일이없는 경우 존재하지 않는 파일 이름을 처리하지 않고 루프가 종료되도록합니다 *.java. 에서 bash(비슷한 지원 또는 쉘), 당신은 사용할 수 있습니다 nullglob단순히 실패 일치를 무시하고 루프의 시체를 입력하지 옵션을 선택합니다.

shopt -s nullglob
for i in *.java; do
    ...
done

5
가장 간단한 방법은 다른 패턴을 추가하는 것입니다 : for i in *.java *.cpp; do. 당신이 활성화 패턴을 확장 한 경우 bash와를 shopt -s extglob, 당신은 쓸 수 있습니다 for i in *.@(java|cpp); do.
chepner

8
실제로 어떤 파일과 일치하면됩니다. shopt -s nullglob일치하지 않는 패턴이 문자 그대로 처리되지 않고 빈 시퀀스로 확장되도록 사용해야 합니다.
chepner

1
@zygimantus 그렇습니다. 현재 디렉토리가 스크립트가 실행되는 곳이면됩니다. 당신이 디렉토리에없는 경우에 당신은 당신이해야하지만되고 싶어 cd당신이 시작하기 전에 그 디렉토리로 for루프
danielsdesk

1
@puk 쉘 옵션에 따라 다릅니다. 기본적으로 일치하지 않는 패턴은 리터럴 문자열로 처리됩니다. 당신은 설정할 수 있습니다 nullglob, 하늘의 순서, 또는 세트로 처리 한 것으로 failglob는 오류로 처리 한 것으로. (둘 다 설정 failglob하면 우선 적용됩니다.)
chepner

3
@chepner 누군가 복사하여 붙여넣고 작동하지 않을 수 있으므로 전문가가 아닌 경우 답변에 이것을 표시하는 것이 유용 할 수 있습니다. 완벽한 예는 중요한 기능을 수행하기 전에 모든 " .jpg"파일을 " .png" 로 변환하는 사람입니다
puk

13

정답은 @chepner의

EXT=java
for i in *.${EXT}; do
    ...
done

그러나 다음은 파일 이름에 지정된 확장자가 있는지 확인하는 작은 트릭입니다.

EXT=java
for i in *; do
    if [ "${i}" != "${i%.${EXT}}" ];then
        echo "I do something with the file $i"
    fi
done

ext대신 변수를 사용하면 .java어떻게 될까요?
AR89

13

재귀 적으로 하위 폴더 추가,

for i in `find . -name "*.java" -type f`; do
    echo "$i"
done

find . -name "*.java" -type f -exec echo \{\} \; 출력의 잘못된 구문 분석을 피하기 위해 대신find
umläute

1
그리고 그렇지 않다면 적어도 "$i"루프 안에서 인용해야 합니다.
tripleee 2016-06-07

2
파일 이름에 공백이 있으면 작동하지 않습니다.
codeforester

1
@codeforester 정확히 그 문제가 있었고이
fsinisi90

7

: 루프로 끝나는 모든 파일을 통해 .img, .bin, .txt접미사 및 파일 이름을 인쇄 :

for i in *.img *.bin *.txt;
do
  echo "$i"
done

또는 재귀 적 방식으로 (모든 하위 디렉터리에서도 검색) :

for i in `find . -type f -name "*.img" -o -name "*.bin" -o -name "*.txt"`;
do
  echo "$i"
done

3

파일을 반복하는 올바른 방법에 대한 다른 답변에 동의합니다. 그러나 OP는 다음과 같이 물었습니다.

위의 코드가 작동하지 않습니다. 이유를 아십니까?

예!

훌륭한 기사 테스트의 차이점은 무엇입니까, [및 [[?] 는 다른 차이점 중에서 명령 내에서 expression matching또는 사용할 수 없음을 자세히 설명합니다 ( )pattern matchingtest[

기능 새 테스트 [[이전 테스트 [예

패턴 일치 = (또는 ==) (사용할 수 없음) [[$ name = a *]] || echo "이름이 'a'로 시작하지 않습니다 : $ name"

정규식 = ~ (사용할 수 없음) [[$ (날짜) = ~ ^ 금 \ ... \ 13]] && echo "13 일의 금요일입니다!"
어울리는

따라서 이것이 스크립트가 실패하는 이유입니다. OP가 [[구문 ( [명령 만큼 많은 플랫폼에서 지원되지 않는 단점이 있음) 을 사용한 답변에 관심이 있다면 답변을 포함하도록 편집 해 드리겠습니다.

편집 : 답변의 데이터를 표로 형식화하는 방법에 대한 모든 protips가 도움이 될 것입니다!


2

@chepner가 그의 의견에서 말했듯이 $ i를 고정 문자열과 비교하고 있습니다.

상황을 확장하고 수정하려면 정규식 연산자 = ~와 함께 [[]]를 사용해야합니다.

예 :

for i in $(ls);do
    if [[ $i =~ .*\.java$ ]];then
        echo "I want to do something with the file $i"
    fi
done

= ~의 오른쪽에있는 정규식은 왼손 연산자의 값에 대해 테스트되며 따옴표로 묶어서는 안됩니다 (따옴표는 오류가 아니지만 고정 문자열과 비교하므로 실패 할 가능성이 높습니다. "

그러나 glob을 사용하는 위의 @chepner의 대답은 훨씬 더 효율적인 메커니즘입니다.


ext대신 변수를 사용하면 .java어떻게 될까요?
AR89

1
ack, 정규 표현식 필요 없음 : if [[ $i == *.java ]]또는 if [[ $i == *.$ext ]]. 그러나 하지 구문 분석 LS 할
글렌 잭맨

1

이 솔루션이 매우 편리하다는 것을 알았습니다. 다음 -or옵션을 사용합니다 find.

find . -name \*.tex -or -name "*.png" -or -name "*.pdf"

확장자 texpng, 및 pdf.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.