중첩 된 디렉토리 평탄화


71

이것은 아마도 매우 간단하지만 이해할 수 없습니다. 다음과 같은 디렉토리 구조가 있습니다 (dir2는 dir1 안에 있습니다).

/dir1
    /dir2 
       |
        --- file1
       |
        --- file2

dir2가 아닌 dir1에서 file1과 file2를 얻는 방식 으로이 디렉터 구조를 '평평하게'하는 가장 좋은 방법은 무엇입니까?


답변:


75

GNU find와 GNU 로이 작업을 수행 할 수 있습니다 mv.

find /dir1 -mindepth 2 -type f -exec mv -t /dir1 -i '{}' +

기본적으로 find전체 디렉토리 트리를 통과하고 -type f최상위 디렉토리 ( -mindepth 2)에 없는 각 파일 ( ) 에 대해 작동하는 방식은 원하는 디렉토리 ( ) mv로 이동합니다 -exec mv … +. -t인수 할 mv수 있습니다 당신이 필요로하는, 먼저 대상 디렉토리를 지정하기 때문에 +형태 -exec명령의 끝에 풋 모든 소스 위치. -i차종은 mv어떤 중복을 덮어 쓰기 전에 물어; -f묻지 않고 -n덮어 쓰거나 요청하거나 덮어 쓰지 않고 대체 할 수 있습니다 .

Stephane Chazelas가 지적했듯이 위의 내용은 GNU 도구 (Linux의 표준이지만 대부분의 다른 시스템은 아닙니다)에서만 작동합니다. 다음은 mv여러 번 호출하기 때문에 다소 느리지 만 훨씬 보편적입니다.

find /dir1 -mindepth 2 -type f -exec mv -i '{}' /dir1 ';'

3
-exec +다수의 프로세스를 실행하지 않도록 사용 하도록 편집되었습니다.mv
Random832

1
@ Random832 +가 작동하지 않기 때문에 다시 되돌릴 것입니다. mv대상은 최종 인수로 필요하지만 +는 최종 인수로 소스를 갖습니다. 심지어 늘 찾기 동의 구문을 당신은 (그것을 변경 find: missing argument to `-exec')
derobert

1
@ Random832하지만 난 가정은 mv-t우리가 사용할 수있는, 그래서 나는 그로 변경됩니다.
derobert

1
@Dom find은 기본적으로 숨겨진 (도트) 파일을 인쇄합니다. 깊이는 찾으려는 디렉토리를 기준으로합니다.
derobert

1
또는 find ./dir -mindepth 2 -type f -exec mv -f '{}' ./dir ';'중복을 재정의하는 경우
Atav32

33

zsh에서 :

mv dir1/*/**/*(.D) dir1

**/하위 디렉토리를 재귀 적으로 탐색합니다. 글로브 한정자는 . 정규 파일과 일치하고, D(기본, 이름이 시작하는을 가진 파일이 점 파일이 포함되도록 .와일드 카드에서 제외됩니다 일치). 이후에 비어있는 디렉토리를 정리하려면 다음을 실행하십시오. rmdir dir1/**/*(/Dod)/디렉토리로 제한 od하고 일치 항목을 먼저 제거하여 dir1/dir2/dir3before 제거하십시오 dir1/dir2.

파일 이름의 총 길이가 너무 길면 명령 줄 길이에 제한이있을 수 있습니다. Zsh에는 이 제한에 영향을 미치지 않는 내장 기능이 mv있으며 rmdir이를 zmodload zsh/files사용 하려면 실행하십시오 .

POSIX 도구 만 사용 :

find dir1 -type f -exec mv {} dir1 \;
find dir1 -depth -exec rmdir {} \;

또는 (각 파일마다 별도의 프로세스를 실행할 필요가 없기 때문에 더 빠름)

find dir1 -type f -exec sh -c 'mv "$@" dir1' _ {} +
find dir1 -depth -exec rmdir {} +

1
이것이 정답입니다! 간결한 zsh 버전의 경우 특히 그렇습니다.
Adamski

3

이것을 시도하십시오 :

cp /dir1/dir2/file{1,2} /another/place

또는 file[0-9]*subdir에서 일치하는 각 파일에 대해 :

cp /dir1/dir2/file[0-9]* /another/place

http://mywiki.wooledge.org/glob를 참조 하십시오


나는 이것을 표시해야했지만 {}실제 문제 에 사용하려면 많은 파일이 있어야합니다 .
turtle

내 두 번째 솔루션보기
Gilles Quenot

빙고. 도와 주셔서 감사합니다. 이것은 확실히 최고의 솔루션입니다.
turtle

2

함께 사용할 수있는 두 가지 기능을 작성했습니다 -maxdepth $VAL. 매개 변수 를 추가하여 디렉토리 수준을 제한 할 수 있습니다 .

# This scripts flattens the file directory
# Run this script with a folder as parameter:
# $ path/to/script path/to/folder

#!/bin/bash

rmEmptyDirs(){
    local DIR="$1"
    for dir in "$DIR"/*/
    do
        [ -d "${dir}" ] || continue # if not a directory, skip
        dir=${dir%*/}
        if [ "$(ls -A "$dir")" ]; then
            rmEmptyDirs "$dir"
        else
            rmdir "$dir"
        fi
    done
    if [ "$(ls -A "$DIR")" ]; then
        rmEmptyDirs "$DIR"
    fi
}

flattenDir(){
    local DIR="$1"
    find "$DIR" -mindepth 2 -type f -exec mv -i '{}' "$DIR" ';'
}

read -p "Do you wish to flatten folder: ${1}? " -n 1 -r
echo    # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]
then
    flattenDir "$1" &
    rmEmptyDirs "$1" &
    echo "Done";
fi

남자, 방금 서버를 망쳐 놓은 경로 인수를 잊어 버려서 스크립트를 잘못 사용했습니다. 좋아, 나는 물건을 복사하여 오용하는 사람이지만, 현명하고, 물건을 삭제 / 이동하는 스크립트에 대한 확인 / 확인을 추가하십시오.
dulgan

으악! 유감입니다. 백업 해 주셨으면 좋겠습니다. 향후 보호를 위해 확인을 추가했습니다.
Bruno

이 방법으로 훨씬 나은 @Bruno에게 감사드립니다. 내 서버는 여전히 완벽하게 실행 중입니다. "평평한"부분에 주석을 달아서 스크립트 실행을 중지시키는 오류가 나타날 때까지 루트 디렉토리에서 빈 디렉토리를 재귀 적으로 삭제했습니다 (그리고 내 오류였습니다).
dulgan

1

동일한 이름의 파일을 포함하는 디렉토리를 평탄화하기위한 유스 케이스가 있었 으므로이 질문에 대한 인기있는 답변을 확장했습니다.

dir1/
├── dir2
   └── file
└── dir3
    └── file

이 경우 전달 된 -i( --interactive) 옵션 mv은 디렉토리 구조를 평탄화하고 이름 충돌을 처리하기 위해 원하는 결과를 얻지 못합니다. 그래서 단순히으로 대체 것 --backup=t(상당 --backup=numbered). 온 더 문서 -b( --backup에서 구입 가능) 옵션 https://www.gnu.org/software/coreutils/manual/coreutils.html#Backup-options .

를 야기하는:

find dir1/ -mindepth 2 -type f -exec mv -t dir1/ --backup=t '{}' +

산출량 :

dir1/
├── dir2
├── dir3
├── file
└── file.~1~

1

tar와 zip은 둘 다 디렉토리 구조를 통합 한 다음 제거 할 수 있으므로 중첩 된 디렉토리를 신속하게 병합 할 수있었습니다.

tar -cvf all.tar *

all.tar를 새 위치로 이동 한 다음

tar -xvf all.tar --strip=4

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.