유닉스 쉘 스크립팅 : 한 디렉토리로 파일을 재귀 적으로 이동하는 방법?


8

나는 디렉토리 구조로 배열 된 많은 수의 작은 파일 f를 가지고있다 :

/A/B/C/f

A 레벨에는 11 개의 디렉토리가 있으며, 각각 B 레벨에는 약 100 개의 디렉토리가 있으며, 각각 C 레벨에는 약 30 개의 디렉토리가 있으며, 각각 하나의 파일이 있습니다 f.

모든 파일을 한 레벨 위로 이동하려면 어떻게합니까? 예를 들어,이 파일 세트가 주어진다면 ...

/ A / B / C / f1
/ A / B / C / f2
/ A / B / C / f3
/ A / B / C / f4

디렉토리 /A/B/에 f1에서 f4까지 4 개의 파일이 포함 되기를 원합니다 . 디렉토리 C를 제거 할 필요는 없습니다.

나는 아마도 포함, 해결 된 문제이있다 바라고 있어요 find, xargs하고 whatnot. 어떤 아이디어?

건배,

제임스

답변:


9

GNU find (Linux에서 찾은) 또는 다음을 지원하는 다른 find를 사용하면 상당히 간단합니다 -execdir.

find A -type f -execdir mv -i {} .. \;

표준으로 find:

find A -type f -exec sh -c 'mv -i "$1" "${1%/*}/.."' sh {} \;

zsh로 :

zmv -Q -o-i 'A/(**/)*/(*)(.)' 'A/$1$2'

디렉토리 구조가 항상 동일한 중첩 레벨을 갖는 경우 재귀 순회가 필요하지 않지만 먼저 빈 디렉토리를 제거하십시오.

for x in */*; do; echo mv -i "$x"/*/* "$x"/..; done

1

해당 파일 세트의 경우 다음을 수행하십시오.

$ cd /A/B/C/
$ mv ./* ../

그러나 나는 당신의 문제가 다소 더 복잡 할 것으로 기대하고 있습니다 ... 나는 이것에 대답 할 수 없습니다 ... 나는 당신의 dir 구조가 어떻게되는지 확실하지 않습니다 ... 명확히 할 수 있습니까?


이것은 분명히 하나의 디렉토리 / A / B / C에 대해 작동하지만 약 30000 개의 디렉토리가 있으므로 계층 구조의 최상위에서 실행될 수있는 명령을 사용하여 한 번에 모두 처리 할 수 ​​있기를 바랍니다.
jl6

1
@ jl6 알겠습니다. 파일 만 이동해야합니까? 따라서 C는 B로 이동하지 않아도되고 B는 A 등으로 이동하지 않아도됩니다.
스택 오버플로가 종료되었습니다.

맞습니다. 작업은 파일의 계층에서 가장 낮은 수준에서만 수행해야하며 한 수준 위로 만 이동해야합니다.
jl6

0

내 첫 번째 추측은

$ find A -type f -exec mv {} .. \;  

지정하지 않으면 -depth괜찮습니다. 나는 그것을 시도하지 않았으므로 커밋하기 전에 먼저 테스트하십시오.


같은 이름을 가진 두 개의 파일이있을 때 어떤 작업을 수행합니까?

찾기는 문제가 아니며 내장 된 "mv"명령입니다. mv가 이름을 바꾸지 않기 때문에 속임수 이름이 좋지 않을 것입니다. 덮어 씁니다. mv -i를 사용하면 약간 도움이 될 수 있지만 30,000 개 이상의 파일이 있으면 고통 스러울 수 있습니다. 상황을 많이 제어 해야하는 경우 스크립팅 언어로 작성된 프로그램이 필요할 수 있습니다 (파이썬, YMMV 선택).
hotei

mv와 함께 "백업"을 사용하지는 않았지만 맨 페이지를 보면 그것이 듀피 이름 문제에 대한 해결책 일 것 같습니다. "find A -type f -exec mv --backup numbered {} .. \;" 작동 할 수도 있습니다 (--backup에서 이중 대시 임)
hotei

주어진 찾기 예제는 가장 낮은 레벨의 모든 파일을 A보다 높은 디렉토리로 이동합니다 ( ".."는 find / mv로 전달되기 전에 쉘에 의해 해석되고 있다고 생각합니까?). 계층 구조에서 한 수준 위로 이동하려면 파일이 필요합니다. 한 가지 추가 설명 : 파일이 한 수준 위로 만 이동하는 한 파일 이름이 중복되지 않습니다.
jl6

@hotei : mv명령은 현재 디렉토리에서 실행되므로 ..원하는 작업을 수행하지 않습니다. 솔루션에 대한 내 답변 을 참조하십시오 . @ jl6 : 쉘은 ..커널과 관련이 있습니다.
Gilles 'SO- 악마 중지'

0

리프 디렉토리에있는 파일 만 이동하려는 경우 (즉, 서브 디렉토리 가 포함 된 경우 이동하지 않으려 /A/B/file/A경우 B) 다음과 같은 몇 가지 방법이 있습니다.

둘 다 이것을 요구합니다

leaf ()
{
    find $1 -depth -type d | sed 'h; :b; $b; N; /^\(.*\)\/.*\n\1$/ { g; bb }; $ {x; b}; P; D'
}
shopt -s nullglob

이것은 작동합니다 :

leaf A | while read -r dir
do
    for file in "$dir"/*
    do
        parent=${dir%/*}
        if [[ -e "$parent/${file##*/}" ]]
        then
            echo "not moved: $file"
        else
            mv "$file" "$parent"
        fi
    done
done

이것은 더 빠를 것이지만, 빈 소스 디렉토리를 좋아하지 않습니다 :

leaf A | while read -r dir
do
    mv -n "${dir}"/* "${dir%/*}"
    remains=$(echo "$dir"/*)
    [[ -n "$remains" ]] && echo "not moved: $remains"
done
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.