두 개의 bash 배열이 있는데 하나(이름 toMove
)에는 파일과 디렉터리에 대한 경로가 포함되어 있습니다.이동(복사 아님)다른 위치에는 exclude
이동에서 제외할 파일 및 디렉터리의 경로가 포함된 또 다른 파일( )이 포함되어 있습니다.
toMove=(
tree/subtree1
tree/subtree2
tree/subtree3/leaffile3
)
exclude=(
tree/subtree1/leafdir1
tree/subtree2/leaffile2
)
# move code ?
테스트 디렉터리 구조는 다음과 같습니다.
mkdir -p tree/{subtree1/leafdir1,subtree2/leafdir2,subtree3/leafdir3}
touch tree/{subtree1/leaffile1,subtree2/leaffile2,subtree3/leaffile3}
tree tree
tree
├── subtree1
│ ├── leafdir1
│ └── leaffile1
├── subtree2
│ ├── leafdir2
│ └── leaffile2
└── subtree3
├── leafdir3
└── leaffile3
이사 후 예상되는 사항:
tree tree
tree
├── subtree1
│ └── leafdir1
├── subtree2
│ └── leaffile2
└── subtree3
└── leafdir3
tree destination
destination
├── subtree1
│ └── leaffile1
├── subtree2
│ └── leafdir2
└── subtree3
└── leaffile3
(이것과 결합하여 ) 내가 원하는 것을 정확하게 수행하는 rsync
옵션 이 있지만 불행히도--exclude-from=
--remove-source-files
rsync
파일을 복사하지만 나한테는 필요해이동하다그들을(성능상의 이유로) 동일한 파일 시스템에 있는 경우.
내가 생각해낸 해결책은 find를 사용하여 toMove 배열의 모든 경로(디렉토리 내용 포함) 목록을 가져오고, 이 목록을 반복하고, 제외 배열의 경로로 시작하는 모든 경로를 필터링하는 것입니다. 이것이 문제를 해결하는 올바른 방법입니까, 아니면 이 문제를 해결하는 더 간단하고 우아한 방법(일부 표준 유틸리티 사용)이 있습니까?
고쳐 쓰다:
문제는 처음 볼 때 생각하는 것만큼 사소하지 않으며 질문의 표현도 좋지 않은 것으로 밝혀졌습니다. "다른 경로의 경로를 필터링하고 영향을 받지 않은 전체 트리를 보호하는 것"에 관한 것이어야 합니다.
나는 빈 리프 디렉토리를 유지하지 않지만 아래 솔루션으로 끝났으며 모든 파일을 이동하고 어떤 경우에는 충분할 때 부모 트리만 이동한다는 두 번째 단점이 있습니다.
...
comm \
-23 \
<(find "${toMove[@]}" ! -type d 2>/dev/null | sort -u || true) \
<(find "${exclude[@]}" ! -type d 2>/dev/null | sort -u || true) |
parallel -j "$(nproc)" -- moveFile {}
...
(moveFile은 이동을 처리하는 데 사용되는 내보낸 bash 함수입니다. 스크립트가 파일 시스템에서 실행되지 않을 때 작업 속도를 높이려면(몇 번) 병렬을 사용하세요.
Stefan Chazeras의 답변zsh
제가 예전에 몰랐던 것들을 많이 알려주셨고, 선택권이 주어진다면 이 길이 좋을 것 같습니다.
답변1
모든 소스와 대상이 동일한 파일 시스템에 있는 경우 move는 a이며 기본적으로 rename()
+와 동일합니다.link()
unlink()
표준(광범위하지는 않지만) pax
명령, (이전의 표준) 명령 및 cpio
GNU 구현 with with 는 디렉토리 구조를 기호 링크로 복사할 수 있습니다(여전히 재생성되어야 하는 디렉토리에는 적용되지 않음). ( / ) 및 ( / 옵션 )을 사용하여 GNU 구현을 수행할 수 있습니다.cp
-al
zsh
bash
cpio
-0
--null
rm
-d
--dir
#! /bin/zsh -
src=tree
dst=destination
toMove=(
subtree1
subtree2
subtree3/leaffile3
)
exclude=(
subtree1/leafdir1
subtree2/leaffile2
)
set -o extendedglob
autoload zargs
src=$src:P
dst=$dst:P
cd -- $src || exit
allToMove=( $^toMove{,/**/*}~(${(~j[|])exclude})(|/*)(ND) )
print -rNC1 -- $allToMove |
cpio --pass-through --null --link --make-directories -- $dst &&
zargs -r -- ${(Oa)allToMove} -- rm -d --
우리는 방금 이름을 바꿀 수 있었던 디렉터리까지 포함하여 모든 대상 디렉터리를 다시 생성하고 그 안에 있는 모든 파일을 연결하게 되므로 여전히 개선이 될 수 있지만 적어도 디렉터리가 아닌 파일에 대한 데이터는 복사되지 않았습니다.
--make-directories
이동할 목록에 포함되지 않아 생성된 디렉터리(예: 디렉터리)에는 subtree3
소스에서 해당 메타데이터(소유권, 권한 등)가 복사되지 않습니다.
디렉터리가 비어 있지 않기 때문에 디렉터리를 삭제할 수 없다는 경고가 표시됩니다.
사용되는 zsh 기능 중 일부는 다음과 같습니다.
$var:P
$var
마치 표준을 사용하는 것처럼 저장된 파일의 절대 표준 경로로 확장됩니다 (realpath()
입력할 때 필요하므로 이후 상대 경로는 더 이상 동일한 파일을 참조하지 않습니다).$dst
cd
$src
destination
$^array/x
/ 와 같은 배열을 확장합니다rc
. 예를 들어 및 요소가 포함된 경우 대신 이 됩니다.fish
$array
A
B
Ax
Bx
A
Bx
A{x,y}
csh와 유사한 중괄호 확장이며, , 로도 확장 됩니다Ax
.Ay
**/
모든 수준의 하위 디렉터리와 일치합니다.- in 은
glob~pattern
여기에서 제외를 적용하기 위해 사용된~
and-not/Exception 연산자 입니다.extendedglob
(${(~j[|])exclude})(|/*)
j
배열 요소(|
매개변수 확장 플래그로 인해 리터럴이 아닌 전역 연산자로 처리됨)를 추가하여 구성된 제외 패턴으로, 요소 또는 그 안의 파일과 일치하도록 추가합니다.|
~
(|/*)
(ND)
glob 한정자는N
ullglob 및D
otglob을 이러한 glob에 적용하므로 숨겨진 파일이 포함되고 glob이 일치하지 않아도 오류가 생성되지 않습니다.print -rNC1
UL로 구분된 열에 해당 매개변수r
aw를 인쇄합니다.1
C
N
${(Oa)array}
a
역순 으로 확장하여O
잎이 있는 가지보다 먼저 잎이 제거되도록 합니다.zargs
피할 수 있는 것이 있나요?매개변수 목록이 너무 깁니다.삭제할 파일 목록이 너무 많으면 오류가 나타납니다.