기본적으로 1..M개의 디렉터리(DIRA-DIRZ)를 포함하는 상위 디렉터리(PARENT)가 있고 각 디렉터리에는 0..N개의 디렉터리(DIR1-DIRN)가 포함되어 있으며 각 디렉터리에는 파일 목록(FILEa -FILEz)이 포함되어 있습니다. .
PARENT/DIRA/DIR1/files
PARENT/DIRB/files
PARENT/DIRC/DIR2/files
PARENT/DIRC/DIR3/files
...보조 디렉터리(DIR1-DIRN)가 존재하는 경우 파일을 보조 디렉터리(DIR1)에서 이를 포함하는 기본 디렉터리(DIRA)로 이동한 다음 현재 비어 있는 보조 디렉터리(DIR1)를 삭제합니다.
PARENT/DIRA/files
PARENT/DIRB/files
PARENT/DIRC/files
나는 이 조각을 사용하려고 한다는 것을 발견했습니다.
find /thisdir -type f -name "*.ogg" -exec mv {} /somedir \;
하지만 외부 루프와 이를 통합하는 방법을 파악할 수 없습니다.
제공할 수 있는 도움, 특히 설명이 도움이 될 것입니다!
답변1
거의 모든 Linux 배포판(적어도 주요 배포판)에는 Python이 사전 설치되어 있으므로 간단한 Python 스크립트를 작성하는 것이 더 쉬울 수 있습니다.
#!/usr/bin/env python3
import sys
from pathlib import Path
def flatten_and_del(targdir):
pardir = targdir.parent
for f in targdir.glob("*"):
f.rename(pardir / f.name)
targdir.rmdir()
def process_dir(parent):
parent = Path(parent)
if not parent.is_dir():
raise RuntimeError(f"{parent} is not a directory!")
for f in parent.glob("*"):
if not f.is_dir():
continue
flatten_and_del(f)
if __name__ == "__main__":
process_dir(sys.argv[1])
예를 들어 다른 이름으로 저장 tidy-dirs.py
하고 다음과 같이 실행합니다.
python3 tidy-dirs.py path/to/PARENT
경고하다:αГsнιι가 의견에서 언급했듯이 이 접근 방식은~ 할 것이다파일 이름이 충돌하면 데이터가 손실될 수 있습니다. 이런 일이 발생하지 않도록 하려면 실행하기 전에 확인을 flatten_and_del
추가하세요 .target.exists()
.rename()
답변2
그리고 zsh
:
autoload zmv # best in ~/.zshrc
zmv '(PARENT)/(*)/*/(*)(#qD)' '$1/$2/$3'
rmdir PARENT/*/*(#qD/^F)
답변3
실제로 이것은 두 가지 명령입니다. 첫 번째는 mv
상위 파일을 삭제하는 것이고, 두 번째는 빈 디렉터리를 삭제하는 것이다.
(두 명령을 하나로 연결하여 &&
한 줄처럼 보이게 합니다.)
find -H PARENT -mindepth 3 ! -type d -execdir cp --backup=numbered -al {} .. \; -delete && find -H PARENT -depth -mindepth 2 -type d -exec rmdir {} +
mv
하드 링크를 생성하고 소스를 삭제하는 대신 . cp
내장된 백업 솔루션 제공:
cp는 --backup=numbered
다른 파일이 이미 존재하는 경우 자동으로 파일 이름을 바꿉니다.
cp -l
는 복사하는 대신 하드 링크를 만듭니다.
cp는 -a
메타데이터(mtime, 권한)를 유지합니다.
find는 -delete
모든 것을 재귀적으로 삭제합니다(주의해서 사용).
설명된 모든 find
주장:
-H
PARENT가 심볼릭 링크인 경우 (= 반전된 인수)와 동일한 항목을 찾습니다. ! -type d
*/*/*/ 레벨 3의 파일만 찾습니다(더 안전하게 만드는 데 사용됨). 하위 디렉터리에서 실행 명령을 찾습니다.-type f
!
-mindepth 3
-maxdepth 3
-execdir
\;
와 설명의 차이점 +
:
CMD ARG1의 직렬 1:1 실행을 찾습니다 -exec CMD {} \;
. ...(여기서 ARG는 find의 결과) CMD ARG1 ARG2 ARG3 ... ARGN의 병렬 실행을
찾습니다 .-exec CMD {} +
PARENT
"$@"
터미널에서 실행하는 대신 여러 인수로 실행되는 작은 셸 스크립트를 교체하고 생성할 수 있습니다 .
sh ./myscript.sh PARENT [PARENT2...]
스크립트 실행
#!/bin/sh
test -e "$1" || exit 1
find -H "$@" -mindepth 3 ! -type d -execdir cp --backup=numbered -al {} .. \; -delete
find -H "$@" -depth -mindepth 2 -type d -exec rmdir {} +
답변4
이 작업을 수행해야 하는 디렉터리가 많은 경우 간단한 bash 스크립트를 사용하여 이 문제를 쉽게 해결하여 시간을 절약할 수 있습니다.
디렉토리는 하나만 있습니다:
parent/
└── DIRA
└── DIR1
├── file1.ogg
├── file2.ogg
└── file3.ogg
그런 다음 DIR1 내부에서 다음을 수행합니다.
# You can also use ; over && but the second one is more reliable,
# specially if you are doing this in a remote server.
mv *.ogg ../ && cd ../ && rmdir DIR1/
결과:
parent/
└── DIRA
├── file1.ogg
├── file2.ogg
└── file3.ogg
보조 디렉터리의 모든 파일이 .ogg라고 확신하는 경우 다음을 사용할 수 있습니다.MV *바꾸다MV*.ogg.