2つのbash配列があり、1つ(名前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配列のすべてのパス(ディレクトリの内容を含む)のリストを取得し、このリストを繰り返し、除外配列のパスで始まるすべてのパスをフィルタリングすることです。これが問題を解決する正しい方法ですか、それともこの問題を解決するより簡単でエレガントな方法(いくつかの標準ユーティリティを使用)がありますか?
修正する:
問題は、初めて見ると思うほど些細ではなく、質問の表現も悪いことがわかりました。 「他のパスのパスをフィルタリングし、影響を受けていないツリー全体を保護すること」に関するものでなければなりません。
私は空のリーフディレクトリを保持しませんが、以下の解決策で終わり、すべてのファイルを移動し、場合によっては十分な場合に親ツリーのみを移動するという2番目の欠点があります。
...
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
避けられるものはありますか?パラメータリストが長すぎます。削除するファイルのリストが多すぎると、エラーが表示されます。