찾기를 사용하여 파일을 이동할 때 디렉토리 구조 유지


22

소스 디렉토리에서 대상 디렉토리로 정의 된대로 이전 파일을 이동하는 다음 스크립트를 작성했습니다. 완벽하게 작동합니다.

#!/bin/bash

echo "Enter Your Source Directory"
read soure

echo "Enter Your Destination Directory"
read destination 

echo "Enter Days"
read days



 find "$soure" -type f -mtime "-$days" -exec mv {} "$destination" \;

  echo "Files which were $days Days old moved from $soure to $destination"

이 스크립트는 파일을 훌륭하게 이동시킵니다. 또한 소스 서브 디렉토리의 파일도 이동하지만 서브 디렉토리를 대상 디렉토리에 작성하지는 않습니다. 이 추가 기능을 구현하고 싶습니다.

예를 들어

/home/ketan     : source directory

/home/ketan/hex : source subdirectory

/home/maxi      : destination directory

이 스크립트를 실행하면 maxi 디렉토리에서 16 진수 파일을 이동하지만 maxi 디렉토리에 동일한 16 진수 파일을 작성하고 동일한 16 진수로 파일을 이동해야합니다.

답변:


13

를 실행하는 대신에서 mv /home/ketan/hex/foo /home/maxi생성 한 경로를 기준으로 대상 디렉토리를 변경해야합니다 find. 먼저 소스 디렉토리로 변경하고 실행하면 더 쉽습니다 find .. 이제는 대상 디렉토리를에서 생성 된 각 항목 앞에 추가 할 수 있습니다 find. find … -exec연결을 수행하고 필요한 경우 대상 디렉토리를 작성하려면 명령 에서 쉘을 실행해야 합니다.

destination=$(cd -- "$destination" && pwd) # make it an absolute path
cd -- "$source" &&
find . -type f -mtime "-$days" -exec sh -c '
  mkdir -p "$0/${1%/*}"
  mv "$1" "$0/$1"
' "$destination" {} \;

$destination특수 문자 가 포함 된 경우 인용 문제를 피하기 위해 쉘 스크립트 내에서이를 대체 할 수는 없습니다. 내부 셸에 도달하도록 환경으로 내보내거나 인수로 전달할 수 있습니다 (내가 한 일). sh호출 을 그룹화하여 약간의 실행 시간을 절약 할 수 있습니다 .

destination=$(cd -- "$destination" && pwd) # make it an absolute path
cd -- "$source" &&
find . -type f -mtime "-$days" -exec sh -c '
  for x do
    mkdir -p "$0/${x%/*}"
    mv "$x" "$0/$x"
  done
' "$destination" {} +

또는 zsh에서 zmvfunction.and m glob 한정자 를 사용하여 올바른 날짜 범위의 일반 파일 만 일치시킬 수 있습니다. mv필요한 경우 먼저 대상 디렉토리를 작성 하는 대체 기능 을 전달해야 합니다.

autoload -U zmv
mkdir_mv () {
  mkdir -p -- $3:h
  mv -- $2 $3
}
zmv -Qw -p mkdir_mv $source/'**/*(.m-'$days')' '$destination/$1$2'

for x do, ;거기 에 누락 이 있습니다 :). 또한, 당신이 무엇을 달성하고 싶었는지 $0모르겠지만 그것이 될 것이라고 확신합니다 sh. :).
Michał Górny

@ MichałGórny는 for x; do(체크 기술적으로 POSIX 호환되지 않습니다 문법 ), 그러나 현대 쉘은 모두 허용 for x dofor x; do; 일부 오래된 Bourne 포탄은 grok하지 않았다 for x; do. 현대 쉘,에 sh -c '…' arg0 arg1 arg2 arg3, arg0된다 $0, arg1된다 $1당신이 원하는 경우 등 $0으로 sh, 당신은 작성해야합니다 sh -c '…' sh arg1 arg2 arg3. 다시, 일부 Bourne 쉘은 다르게 동작하지만 POSIX는이를 지정합니다.
Gilles 'SO- 악마 그만해

pushdcd현재 환경에 덜 영향을 미치기 때문에 더 나은 선택 인 것 같습니다 .
jpmc26

16

find지정된 것으로 알고 있지만의 직업처럼 들립니다 rsync.

가장 자주 다음을 사용합니다.

rsync -axuv --delete-after --progress Source/ Target/

다음은 특정 파일 형식의 파일 만 이동하려는 경우에 좋은 예입니다 ( example ).

rsync -rv --include '*/' --include '*.js' --exclude '*' --prune-empty-dirs Source/ Target/

다른 솔루션보다 훨씬 깨끗합니다 :)

2
그 발견 --remove-source-files효율적으로 이동하는 대신 복사 할 파일을 일으키는, 도움이되었다. 이것은 rsync를 훌륭하게 사용합니다.
Tom

3

find (1)의 두 인스턴스를 사용하여 수행 할 수 있습니다

항상 cpio (1)가 있습니다

(cd "$soure" && find  | cpio -pdVmu "$destination")

cpio의 인수를 확인하십시오. 내가 준 것들


1
공백이있는 모든 파일 이름이 손상됩니다.
Chris Down

1
파일을 이동하지 않고 복사합니다.
Gilles 'SO- 악마 중지

완벽한 대답은 아니지만 경로를 유지하는 파일을 다소 직선적으로 이동하는 데 도움이되었습니다 (파일을 복사 한 다음 삭제하기에 충분한 공간이 있습니다). 공감
AhHatem

3

그것은 효율적이지 않지만, 파일을 복사 한 다음 나중에 삭제하면 코드를 읽고 이해하기 쉽습니다.

find /original/file/path/* -mtime +7 -exec cp {} /new/file/path/ \;
find /original/file/path/* -mtime +7 -exec rm -rf {} \;

알림 : 자동화 된 작업을 위해 @MV가 발견 한 결함 :

두 개의 개별 작업을 사용하는 것은 위험합니다. 복사 작업을 수행하는 동안 일부 파일이 7 일보다 오래된 경우 파일은 복사되지 않지만 삭제 작업으로 삭제됩니다. 한 번 수동으로 수행되는 작업은 문제가되지 않지만 자동화 된 스크립트의 경우 데이터가 손실 될 수 있습니다.


2
두 개의 개별 작업을 사용하는 것은 위험합니다. 복사 작업을 수행하는 동안 일부 파일이 7 일보다 오래된 경우 파일은 복사되지 않지만 삭제 작업으로 삭제됩니다. 한 번 수동으로 수행하는 작업은 문제가되지 않지만 자동화 된 스크립트의 경우 데이터가 손실 될 수 있습니다.
MV.

2
이 결함에 대한 쉬운 해결책은 찾기를 한 번 실행하고 목록을 텍스트 파일로 저장 한 다음 xargs를 두 번 사용하여 복사 한 다음 삭제하는 것입니다.
David M. Perlman

1

find대상 경로에 반환 된 파일의 절대 경로를 추가하여이 작업을 수행 할 수 있습니다 .

find "$soure" -type f -mtime "-$days" -print0 | xargs -0 -I {} sh -c '
    file="{}"
    destination="'"$destination"'"
    mkdir -p "$destination/${file%/*}"
    mv "$file" "$destination/$file"'

맥시로 크리스는 이제 이동 전체 집
케탄 파텔

@ K.KPatel 아니오, 그렇지 않습니다. 단순히 디렉토리 구조를 유지합니다.
Chris Down

$destination내부 문자가 확장되기 때문에 특수 문자 가 포함되어 있으면 중단됩니다 . 아마 당신은 의미 destination='\'"$destination"\''? 여전히 계속되고 '있습니다. 또한 이것은 /home/maxi/home/ketan/hex/foo대신 같은 파일을 만듭니다 /home/maxi/hex/foo.
Gilles 'SO- 악마 그만

0

파일 이름에 특수 문자가 포함되어 있으면 파일 이름의 영향을받지 않습니다.

export destination
find "$soure" -type f "-$days" -print0 | xargs -0 -n 10 bash -c '
for file in "$@"; do
  echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
  mkdir -p "$destination"/`dirname "$file"`
  \mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
done'

또는 "parallel"명령을 사용하여 여러 CPU에서 동시에 여러 파일을 이동하는 것이 더 빠릅니다.

echo "Move oldest $days files from $soure to $destination in parallel (each 10 files by "`parallel --number-of-cores`" jobs):"
function move_files {
  for file in "$@"; do
    echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
    mkdir -p "$destination"/`dirname "$file"`
    \mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
  done
}
export -f move_files
export destination
find "$soure" -type f "-$days" -print0 | parallel -0 -n 10 move_files

추신 : 오타가 있습니다. "순수"는 "소스"여야합니다. 변수 이름을 유지했습니다.


0

파일 수 / 크기가 너무 크지 않으면 우아하지 않지만 쉽습니다.

파일 zip을 압축 파일 로 압축 한 다음 -j옵션 없이 대상에서 압축을 풉니 다 . 기본적으로 zip은 상대 디렉토리 구조를 만듭니다.


0

이 방법으로 시도하십시오 :

IFS=$'\n'
for f in `find "$soure" -type f -mtime "-$days"`;
do
  mkdir -p "$destination"/`dirname $f`;
  mv $f "$destination"/`dirname $f`;
done

0

이것에 대한 쉬운 해결책이없는 것 같고 매우 자주 필요하기 때문에 Linux 용 오픈 소스 유틸리티를 만들었습니다 (파이썬 필요) : https://github.com/benapetr/smv

필요한 것을 달성하는 데 여러 가지 방법이 있지만 가장 간단한 방법은 다음과 같습니다.

 # -vf = verbose + force (doesn't stop on errors)
smv -vf `find some_folder -type f -mtime "-$days"` target_folder

건조 모드에서 추가로 실행할 수 있으므로 아무것도하지 않고 인쇄 할 수 있습니다.

smv -rvf `find some_folder -type f -mtime "-$days"` target_folder

또는 파일 목록이 너무 길어서 인수 줄에 맞지 않고 모든 단일 파일에 대해 파이썬을 실행하는 것을 신경 쓰지 않는 경우

find "$soure" -type f -mtime "-$days" -exec smv {} "$destination" \;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.