재귀적 파일 및 디렉터리 작업

재귀적 파일 및 디렉터리 작업

파일이 포함된 여러 디렉터리에 대해 일련의 작업을 반복적으로 수행하려고 합니다. 각 디렉터리 내에 2개의 디렉터리를 만들고 일부 파일을 각 디렉터리로 이동하고 싶습니다.

예를 들어 내 디렉토리 구조는 다음과 같습니다.

   root --
     subdirectory1 --
         file_a1_a.tif
         file_a2_a.tif
         file_a1_b.tif
         file_a2_b.tif
     subdirectory2 --
         file_b1_a.tif
         file_b2_a.tif
         file_b1_b.tif
         file_b2_b.tif

파일을 이렇게 정리하고 싶은데...

   root --
     subdirectory1 --
         subdirectory_a --
             file_a1_a.tif
             file_a2_a.tif
         subdirectory_b --
             file_a1_b.tif
             file_a2_b.tif
     subdirectory2 --
         subdirectory_a --
             file_b1_a.tif
             file_b2_a.tif
         subdirectory_b --
             file_b1_b.tif
             file_b2_b.tif

나는 다음을 수행하고 있지만 최상위 디렉토리에서만 작동하는 것 같습니다.

find . -type d -execdir bash -c "mkdir -p subdirectory_a && mkdir -p subdirectory_b && mv *_a.tif subdirectory_a 2>/dev/null && mv *_b.tif subdirectory_b 2>/dev/null" \;

어떤 도움이라도 대단히 감사하겠습니다.

답변1

root자식만 있고 손자는 없으므로 디렉터리에서 다음을 실행할 수 있습니다 root.

subA='subdirectory_a'
subB='subdirectory_b'
for d in */; do
    mkdir -p "$d$subA" "$d$subB"
    mv "$d"*_a.tif "$d$subA"
    mv "$d"*_b.tif "$d$subB"
done

$dand 로 확장되는 for 루프의 glob 때문에 subdirectory1/직접 하위 디렉터리에만 일치합니다. 해당 손자 파일(이미 존재하는 경우 불평하지 않도록 존재)을 만든 다음 와일드카드를 다시 사용하여 파일을 손자 파일로 이동합니다.subdirectory2/*/rootmkdir-p

쉘이 glob을 확장하려는 경우 이를 인용 해제해야 합니다. 그렇기 때문에 mv "$d"*_a.tif "$d$subA"맞지만 mv "$d*_a.tif" "$d$subA"정확하지 않습니다.

답변2

질문에 게시 한 명령

find . -type d -execdir bash -c "mkdir -p subdirectory_a && mkdir -p subdirectory_b && mv *_a.tif subdirectory_a 2>/dev/null && mv *_b.tif subdirectory_b 2>/dev/null" \;

올바르게 작동합니다(즉, 해야 할 일을 수행합니다). 그러나 그것이 표현하는 것은 당신이 원하는 것이 아닙니다.

이 매개변수는 "...지정된 명령은 -execdir일치하는 파일이 포함된 하위 디렉터리에서 실행됩니다"(소스 코드,
찾기(1))

즉, 현재 작업이 직접적이고 root명령이 이를 대상으로 하는 subdirectory1경우 예상한 대로 드롭다운되지 않습니다. 내부에서 subdirectory1일치하는 항목이 -type d발견되었으므로 해당 위치에 머무르며 거기에서 지정된 명령을 실행합니다. 물론, 그 안에 파일이 없기 때문에 아무것도 이동되지 않을 것이지만, 또한 다음과 같은 오류가 발생하지 않을 것이라는 점도 주의하십시오.findrootmkdirrootmkdir -p목차(1): "있는 경우 오류가 없습니다."


그렇다면 이 게임을 여러분이 원하는 게임으로 만들려면 어떻게 해야 할까요? 동일한 구조를 게시했다고 가정해 보겠습니다.

$ tree /tmp/root
/tmp/root
├── subdir1
│   ├── file_a1_a.tif
│   ├── file_a1_b.tif
│   ├── file_a2_a.tif
│   └── file_a2_b.tif
└── subdir2
    ├── file_b1_a.tif
    ├── file_b1_b.tif
    ├── file_b2_a.tif
    └── file_b2_b.tif

세 단계로 나누는 것이 좋습니다. 모든 작업을 수행하기 위해 하나의 명령을 사용할 필요가 없습니다. '코드 골프'보다는 원하는 결과에 집중하세요. 그러니 먼저 디렉토리를 만드세요

$ find /tmp/root -maxdepth 1 -mindepth 1 -exec bash -c 'mkdir ${1}/subdirectory_{a,b}' sh  {} \;
$ tree
.
├── subdir1
│   ├── file_a1_a.tif
│   ├── file_a1_b.tif
│   ├── file_a2_a.tif
│   ├── file_a2_b.tif
│   ├── subdirectory_a
│   └── subdirectory_b
└── subdir2
    ├── file_b1_a.tif
    ├── file_b1_b.tif
    ├── file_b2_a.tif
    ├── file_b2_b.tif
    ├── subdirectory_a
    └── subdirectory_b

6 directories, 8 files

그런 다음 디렉터리 트리의 특정 수준에서 일반 파일을 찾아 이동합니다. 이제 우리는 그것을 사용하여 -execdir우리가 원하는 것을 달성할 수 있습니다

$ find /tmp/root -maxdepth 2 -mindepth 2 -type f -execdir bash -c 'case ${1} in *a.tif) echo cp ${1} ./subdirectory_a ;; *b.tif) echo cp ${1} subdirectory_b ;; esac' sh {} \;
cp ./file_b2_b.tif subdirectory_b
cp ./file_b2_a.tif ./subdirectory_a
cp ./file_b1_a.tif ./subdirectory_a
cp ./file_b1_b.tif subdirectory_b
cp ./file_a1_b.tif subdirectory_b
cp ./file_a1_a.tif ./subdirectory_a
cp ./file_a2_b.tif subdirectory_b
cp ./file_a2_a.tif ./subdirectory_a

이 경우 이동하기 전에 에코를 사용하여 모든 것이 제대로 작동하는지 확인하고 실제 이동을 수행하지 않는다는 점에 유의하세요. 따라서 이를 제거하면 echo올바르게 작동합니다.

$ find /tmp/root -maxdepth 2 -mindepth 2 -type f -execdir bash -c 'case ${1} in *a.tif) cp ${1} ./subdirectory_a ;; *b.tif) cp ${1} subdirectory_b ;; esac' sh {} \;
$ tree /tmp/root
/tmp/root
├── subdir1
│   ├── file_a1_a.tif
│   ├── file_a1_b.tif
│   ├── file_a2_a.tif
│   ├── file_a2_b.tif
│   ├── subdirectory_a
│   │   ├── file_a1_a.tif
│   │   └── file_a2_a.tif
│   └── subdirectory_b
│       ├── file_a1_b.tif
│       └── file_a2_b.tif
└── subdir2
    ├── file_b1_a.tif
    ├── file_b1_b.tif
    ├── file_b2_a.tif
    ├── file_b2_b.tif
    ├── subdirectory_a
    │   ├── file_b1_a.tif
    │   └── file_b2_a.tif
    └── subdirectory_b
        ├── file_b1_b.tif
        └── file_b2_b.tif

6 directories, 16 files

물론 이는 데이터 손실을 방지하기 위해 복제를 사용한다는 점에 유의하세요. 우리는 그것을 더 정리할 수 있고 마침내 원하는 디렉토리 트리 구조를 얻습니다.

$ find /tmp/root -maxdepth 2 -mindepth 2 -type f -delete
$ tree 
.
├── subdir1
│   ├── subdirectory_a
│   │   ├── file_a1_a.tif
│   │   └── file_a2_a.tif
│   └── subdirectory_b
│       ├── file_a1_b.tif
│       └── file_a2_b.tif
└── subdir2
    ├── subdirectory_a
    │   ├── file_b1_a.tif
    │   └── file_b2_a.tif
    └── subdirectory_b
        ├── file_b1_b.tif
        └── file_b2_b.tif

6 directories, 8 files

간단히 말해서, 우리가 하는 일은 스크립트로 표현될 수 있습니다.

find /tmp/root -maxdepth 1 -mindepth 1 -exec bash -c 'mkdir ${1}/subdirectory_{a,b}' sh  {} \; &&
find /tmp/root -maxdepth 2 -mindepth 2 -type f -execdir bash -c 'case ${1} in *a.tif) cp ${1} ./subdirectory_a ;; *b.tif) cp ${1} subdirectory_b ;; esac' sh {} \; &&
find /tmp/root -maxdepth 2 -mindepth 2 -type f -delete

물론 대신 사용하면 mv2단계와 3단계가 하나로 압축될 수 있지만 cp데이터 손실 위험을 감수하기보다는 조심하는 편이 낫습니다.

답변3

디렉토리 내에서 실행하면 root명령이 subdirectoy_a최상위 수준에 및 및 및 로 끝나는 모든 파일과 로 끝나는 모든 파일을 이동합니다. 이는 원하는 것이 아닙니다. 이렇게 하면 리디렉션된 오류가 없고 실제로 오류를 볼 수 있는 경우 문제 해결이 더 쉬워집니다. 상위 디렉터리가 이미 존재하므로 옵션이 필요하지 않습니다.subdirectory_bsubdirectory1subdirectory2a.tiffsubdirectory1b.tiffsubdirectory_b/dev/null-pmkdir

가지고 있는 것 대신 root내부(또는 실제 호출 디렉터리)에서 실행하세요.

mkdir subdirectory1/subdirectory_a subdirectory1/subdirectory_b subdirectory2/subdirectory_a subdirectory2/subdirectory_b && mv subdirectory1/file_a*a*  subdirectory1/subdirectory_a && mv subdirectory1/file_a*b*  subdirectory1/subdirectory_b && mv subdirectory2/file_b*a*  subdirectory2/subdirectory_a && mv subdirectory2/file_b*b*  subdirectory2/subdirectory_b

답변4

그리고 zsh:

cd root || exit
subdirs=(*(-/))
mkdir -p -- $^subdirs/subdirectory_{a,b} || exit
autoload -Uz zmv
zmv '(*/)*_(a|b).tif' '${1}subdirectory_$2/$f:t'

필요하다면재귀적subdir1/subsubdir1귀하의 질문에서 알 수 있듯이 (귀하의 예에서는 제안하지 않습니다) 즉, 등에서도 이 작업을 수행해야 하는 경우 *s *(-/)(*/)위의 내용을 로 바꾸십시오 **.

수많은 파일이 있고 속도가 문제인 경우 zsh 내장 명령을 실행 하고 (에 의해 호출됨 zmodload zsh/files) .mkdirmvzmv

하나를 위해시운전zmv그것이 무엇인지만 알려주는 곳회의옵션 을 추가하세요 -n.

각각을 포함하는 디렉토리에 및 를 생성하려는 경우 subdirectory_a다른 접근 방식이 있습니다.subdirectory_b*_a.tif*_b.tif

mkmv() { mkdir -p -- $2:h && mv -- "$@"; }
zmv -P mkmv '(**/)*_(a|b).tif' '${1}subdirectory_$2/$f:t'

(파일은 자신 tif에 있는 root파일 도 이동합니다.)

관련 정보