bash에서 디렉토리 만 반복하는 방법은 무엇입니까?


249

일부 디렉토리와 일부 파일이있는 폴더가 있습니다 (일부는 점으로 시작하여 숨겨져 있습니다).

for d in *; do
 echo $d
done

모든 파일을 반복하지만 디렉토리를 통해서만 반복하고 싶습니다. 어떻게합니까?

답변:


331

디렉토리 만 일치하도록 끝에 슬래시를 지정할 수 있습니다.

for d in */ ; do
    echo "$d"
done

7
디렉토리에 대한 심볼릭 링크도 포함되어 있습니다.
Stéphane Chazelas

1
그렇다면 심볼릭 링크를 어떻게 제외 하시겠습니까?
rubo77

3
@ rubo77 : [[ -L $d ]]$ d가 기호 링크인지 테스트 할 수 있습니다 .
choroba

1
@AsymLabs 정확하지 않습니다 set -P. 디렉토리를 변경하는 명령에만 영향을줍니다. sprunge.us/TNac
Chris Down

4
@choroba : [[ -L "$f" ]]이 경우 심볼릭 링크를 제외하지 않습니다 */. 후행 슬래시를 제거해야합니다 (후행 슬래시가있는 링크 테스트[[ -L "${f%/}" ]] 참조 )
rubo77


30

choroba의 솔루션은 우아하지만 현재 디렉토리 내에 디렉토리가 없으면 예기치 않은 동작을 유발할 수 있습니다. 이 상태에서 for루프를 건너 뛰지 않고 bash는 다음 d과 같은 위치에서 루프를 정확히 한 번만 실행합니다 */.

#!/usr/bin/env bash

for d in */; do
    # Will print */ if no directories are available
    echo $d
done

이 경우를 방지하기 위해 다음을 사용하는 것이 좋습니다.

#!/usr/bin/env bash

for f in *; do
    if [ -d ${f} ]; then
        # Will not run if no directories are available
        echo $f
    fi
done

이 코드는 현재 디렉토리의 모든 파일을 반복 f하고 디렉토리 인지 확인한 다음 f조건이 true를 반환하면 에코 합니다. 경우 f에 동일 */, echo $f실행되지 않습니다.


3
훨씬 쉬워졌습니다 shopt -s nullglob.
choroba 2016 년

21

디렉토리 만보 다 더 구체적인 파일을 선택 해야하는 경우 다음을 사용 find하여 전달하십시오 while read.

shopt -s dotglob
find * -prune -type d | while IFS= read -r d; do 
    echo "$d"
done

shopt -u dotglob숨겨진 디렉토리 (또는 zsh에서 setopt dotglob/) 를 제외하는 데 사용 합니다 unsetopt dotglob.

IFS=$IFS예를 들어, 다음 중 하나를 포함하는 파일 이름이 분할되는 것을 방지합니다 .'a b'

더 많은 옵션에 대해서는 아래 AsymLabs 답변을 참조하십시오find


편집 :
while 루프 내에서 종료 값을 만들어야하는 경우이 트릭으로 여분의 서브 쉘을 우회 할 수 있습니다.

while IFS= read -r d; do 
    if [ "$d" == "something" ]; then exit 1; fi
done < <(find * -prune -type d)

2
: 나는에이 솔루션을 발견 stackoverflow.com/a/8489394/1069083
rubo77

11

순수한 bash를 사용할 수 있지만 find를 사용하는 것이 좋습니다.

find . -maxdepth 1 -type d -exec echo {} \;

(숨겨진 디렉토리를 추가로 찾을 것입니다)


8
디렉토리에 대한 심볼릭 링크는 포함되어 있지 않습니다. 숨겨진 디렉토리를 포함 shopt -s dotglob하는 bash데 사용할 수 있습니다 . 당신도 포함됩니다 .. 또한 -maxdepth표준 옵션이 아닙니다 ( -pruneis).
Stéphane Chazelas

2
dotglob옵션은 흥미롭지 dotglob만의 사용에만 적용됩니다 *. find .은 항상 숨겨진 디렉토리 (및 현재 디렉토리)를 포함합니다
rubo77

6

루트 디렉토리를 제외하고 현재 작업 디렉토리에서 보이는 디렉토리와 숨겨진 디렉토리를 모두 찾기 위해 수행됩니다.

디렉토리를 반복하려면 :

 find -path './*' -prune -type d

결과에 심볼릭 링크를 포함 시키려면 :

find -L -path './*' -prune -type d

심볼릭 링크를 제외한 각 디렉토리에 대해

find -path './*' -prune -type d -print0 | xargs -0 <cmds>

숨겨진 디렉토리를 제외하려면 :

find -path './[^.]*' -prune -type d

반환 된 값에 대해 여러 명령을 실행하려면 (매우 고안된 예) :

find -path './[^.]*' -prune -type d -print0 | xargs -0 -I '{}' sh -c \
"printf 'first: %-40s' '{}'; printf 'second: %s\n' '{}'"

'sh -c'대신 'bash -c'등을 사용할 수도 있습니다.


'for d in echo * /'의 에코 '* /'에 60,000 개의 디렉토리가 포함되어 있으면 어떻게됩니까?
AsymLabs

"너무 많은 파일"오류가 발생하지만 해결 될 수 있습니다 : debian에서 "너무 많은 열린 파일"을 우회하는 방법
rubo77

1
xargs 예제는 디렉토리 이름의 하위 세트 9e에서만 작동합니다. 공백이나 줄 바꿈이있는 사람들은 작동하지 않습니다). ... -print0 | xargs -0 ...정확한 이름이 무엇인지 모르는 경우 사용 하는 것이 좋습니다.
Anthon

1
@ rubo77은 숨겨진 파일 / 디렉토리와 여러 명령의 실행을 제외하는 방법을 추가했습니다. 물론 스크립트로도 수행 할 수 있습니다.
AsymLabs

1
나는 아래 함수에 함수를 사용하여 각 디렉토리에 무언가를하는 방법에 대한 답을 아래에 추가했다.find * | while read file; do ...
rubo77

3

숨겨진 디렉토리 (점으로 시작)를 포함한 모든 디렉토리를 한 줄로 반복하고 다음을 사용하여 여러 명령을 반복 할 수 있습니다.

for file in */ .*/ ; do echo "$file is a directory"; done

심볼릭 링크를 제외하려면 다음을 수행하십시오.

for file in *; do 
  if [[ -d "$file" && ! -L "$file" ]]; then
    echo "$file is a directory"; 
  fi; 
done

참고 : 목록을 사용하는 */ .*/bash는 작동뿐만 아니라 폴더를 표시 .하고 ..폴더에 숨겨진 파일이없는 경우 zsh을에있는 동안이 보여하지만 오류가 발생하지 않습니다

숨겨진 디렉토리를 포함하고 ../를 제외하는 더 깨끗한 버전은 dotglob 옵션과 함께 제공됩니다.

shopt -s dotglob
for file in */ ; do echo "$file is a directory"; done

(또는 setopt dotglobzsh에서)

당신은 dotglob을 해제 할 수 있습니다

shopt -u dotglob

2

목록의 각 디렉토리에 전체 경로가 포함됩니다.

for i in $(find $PWD -maxdepth 1 -type d); do echo $i; done

1
공백이있는 폴더를 사용할 때 중단
Alejandro Sazo

0

findwith -exec를 사용 하여 디렉토리를 반복 하고 exec 옵션에서 함수 를 호출하십시오 .

dosomething () {
  echo "doing something with $1"
}
export -f dosomething
find -path './*' -prune -type d -exec bash -c 'dosomething "$0"' {} \;

사용 shopt -s dotglob또는 shopt -u dotglob숨겨진 디렉토리를 제외 / 포함


0

주어진 경로에있는 모든 하위 디렉토리와 함께 모든 디렉토리를 나열합니다.

for directory in */ ; do D=$(readlink -f "$directory") ; echo $D = $(find "$D" -mindepth 1 -type d | wc -l) ; done

-1
ls -d */ | while read d
do
        echo $d
done

This is one directory with spaces in the name-하지만 여러 개로 구문 분석됩니다.
Piskvor

-5
ls -l | grep ^d

또는:

ll | grep ^d

별명으로 설정할 수 있습니다


1
불행히도, 나는 이것이 디렉토리 ls나열 하는 이 기반 답변과 약간 다른 "디렉토리를 통해서만 루프하고 싶습니다"라는 질문에 대답하지 않는다고 생각합니다 .
Jeff Schaller

1
의 출력을 구문 분석하는 것은 좋은 방법이 아닙니다 ls: mywiki.wooledge.org/ParsingLs을
codeforester
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.