파일이 포함된 여러 디렉터리에 대해 일련의 작업을 반복적으로 수행하려고 합니다. 각 디렉터리 내에 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
$d
and 로 확장되는 for 루프의 glob 때문에 subdirectory1/
직접 하위 디렉터리에만 일치합니다. 해당 손자 파일(이미 존재하는 경우 불평하지 않도록 존재)을 만든 다음 와일드카드를 다시 사용하여 파일을 손자 파일로 이동합니다.subdirectory2/
*/
root
mkdir
-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
발견되었으므로 해당 위치에 머무르며 거기에서 지정된 명령을 실행합니다. 물론, 그 안에 파일이 없기 때문에 아무것도 이동되지 않을 것이지만, 또한 다음과 같은 오류가 발생하지 않을 것이라는 점도 주의하십시오.find
root
mkdir
root
mkdir -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
물론 대신 사용하면 mv
2단계와 3단계가 하나로 압축될 수 있지만 cp
데이터 손실 위험을 감수하기보다는 조심하는 편이 낫습니다.
답변3
디렉토리 내에서 실행하면 root
명령이 subdirectoy_a
최상위 수준에 및 및 및 로 끝나는 모든 파일과 로 끝나는 모든 파일을 이동합니다. 이는 원하는 것이 아닙니다. 이렇게 하면 리디렉션된 오류가 없고 실제로 오류를 볼 수 있는 경우 문제 해결이 더 쉬워집니다. 상위 디렉터리가 이미 존재하므로 옵션이 필요하지 않습니다.subdirectory_b
subdirectory1
subdirectory2
a.tiff
subdirectory1
b.tiff
subdirectory_b
/dev/null
-p
mkdir
가지고 있는 것 대신 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
) .mkdir
mv
zmv
하나를 위해시운전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
파일 도 이동합니다.)