파일 나열을 위한 재귀 쉘 스크립트

파일 나열을 위한 재귀 쉘 스크립트

디렉터리(및 하위 디렉터리)에 있는 특정 유형의 파일을 나열하는 쉘 스크립트를 작성하려고 합니다. 재귀 부분 때문에 어려움을 겪고 있습니다.

이것이 내가 가진 것입니다:

#!/bin/sh

#download dir
DOWNLOADING_DIR=/Users/richard/Downloads

echo "Starting Script..."

for FILE in $DOWNLOADING_DIR/*
do
    if [ -d "$FILE" ]
    then
        echo "...Checking Directory "$FILE
        for DFILE in $FILE/*
        do
            echo "Found file ... $DFILE"
        done
    else
        echo "Found file ... $FILE"
        echo ""
    fi
done

문제는 디렉토리를 찾을 때 디렉토리에서 파일 이름을 찾지 못한다는 것입니다. 하위 디렉터리의 파일이 아닌 하위 디렉터리 이름만 나열됩니다. 첫 번째 디렉터리의 파일에 대해 작동합니다.

.txt 또는 .doc 파일을 검색하여 다른 디렉터리로 이동하려면 이 스크립트가 필요합니다.

답변1

귀하의 스크립트는아니요자신을 호출하지 않기 때문에 재귀적입니다.

비슷한 것을 재귀적으로 구현하는 변형은 다음과 같습니다.

#!/bin/bash

walk_dir () {
    shopt -s nullglob dotglob

    for pathname in "$1"/*; do
        if [ -d "$pathname" ]; then
            walk_dir "$pathname"
        else
            printf '%s\n' "$pathname"
        fi
    done
}

DOWNLOADING_DIR=/Users/richard/Downloads

walk_dir "$DOWNLOADING_DIR"

이 함수는 walk_dir디렉터리 경로 이름을 유일한 인수로 사용하고 해당 내용을 반복합니다. 디렉터리가 발견되면 하위 디렉터리를 탐색하기 위해 자신을 재귀적으로 호출합니다.

.txt파일 이름이 또는 로 끝나는 파일을 찾으려면 이 명령을 수정하세요 .doc.

#!/bin/bash

walk_dir () {    
    shopt -s nullglob dotglob

    for pathname in "$1"/*; do
        if [ -d "$pathname" ]; then
            walk_dir "$pathname"
        else
            case "$pathname" in
                *.txt|*.doc)
                    printf '%s\n' "$pathname"
            esac
        fi
    done
}

DOWNLOADING_DIR=/Users/richard/Downloads

walk_dir "$DOWNLOADING_DIR"

위의 "파일"은 실제로 디렉터리나 디렉터리 심볼릭 링크가 아닌 모든 것을 의미하며 디렉터리와 동일하지 않을 수도 있습니다.일반 파일. 에서 dotglobnullglob쉘 옵션을 설정하면 bash숨겨진 경로 이름을 찾을 수 있으며 잠재적으로 비어 있는 디렉토리를 특별히 테스트할 필요가 없습니다.

이것의 변형은 /bin/sh숨겨진 이름에 신경 쓰지 않습니다.

#!/bin/sh

walk_dir () {
    for pathname in "$1"/*; do
        if [ -d "$pathname" ]; then
            walk_dir "$pathname"
        elif [ -e "$pathname" ]; then
            case "$pathname" in
                *.txt|*.doc)
                    printf '%s\n' "$pathname"
            esac
        fi
    done
}

DOWNLOADING_DIR=/Users/richard/Downloads

walk_dir "$DOWNLOADING_DIR"

globstarexglob쉘 옵션을 사용하면 bash다음을 수행하여(재귀 없이) 파일을 이동할 수도 있습니다.

shopt -s globstar extglob

mv "$DOWNLOADING_DIR"/**/*.@(txt|doc) "$destdir"

...결과 파일 목록이 너무 길지 않은 한. **경로 이름의 슬래시와 일치하고 ( 로 활성화됨 globstar) *.@(txt|doc)또는로 끝나는 모든 파일 이름과 일치합니다 .txt( .doc로 활성화됨 extglob).


특정 최상위 디렉터리 안이나 아래로 끝나는 파일 이름을 가진 일반 파일을 찾아서 .txt다른 디렉터리로 이동하는 보다 효율적이고 이식 가능한 방법입니다..doc$topdir$destdir

find "$topdir" -type f \( -name '*.txt' -o -name '*.doc' \) \
    -exec mv {} "$destdir" \;

GNU를 사용하면 mv더 효율적으로 만들 수 있습니다.

find "$topdir" -type f \( -name '*.txt' -o -name '*.doc' \) \
    -exec mv -t "$destdir" {} +

이 변경사항은 이전됩니다.일괄한 번에 하나의 파일 대신 파일. mvwith를 사용하여 -v이동된 내용을 확인하거나 before를 추가하여 -print라는 -exec경로 이름 목록을 가져옵니다.mv

관련 정보