
Ich versuche, ein Skript zu schreiben, um Dateien rekursiv aus einem bestimmten Ordner zu kopieren, außer files A.extn
, B/*.extn
und C/*
wobei B
und C
Verzeichnisse sind und extn
nur eine generische Erweiterung ist. Das habe ich:
#!/usr/local/bin/zsh
setopt EXTENDED_GLOB
TMPDIR=/tmp/test
cp -pR $(dirname $0)/**~(*.foo/*|*/bar.txt|*.abc|qux.txt) $TMPDIR
Dies führt jedoch nicht wie erwartet zur Negierung des Musters. Ich glaube, ich weiß, warum – obwohl das Muster korrekt ist (wie bei zu sehen echo
), cp -R
ist sich das Muster nicht bewusst und betritt ein Verzeichnis, in das es „nicht gehört“, und sobald es dort ist, ist das Muster nicht mehr gültig.
Wie ändere ich das Obige, um das zu erreichen, was ich will? Ich denke, es ist mit find
und möglich xargs
, aber ich bin von der Klarheit des Obigen angetan und würde etwas Ähnliches bevorzugen (wenn es aber die falsche Vorgehensweise ist, wäre ich mit einer anderen Lösung vollkommen zufrieden).
Antwort1
Sie haben Recht, dass das Muster vor der Ausführung erweitert wird cp
und daher diesem Befehl unbekannt ist.
Möglicherweise können Sie Ihr Ziel erreichen, indem Sie die --parents
Option to cp
anstelle von verwenden -R
. Dadurch werden nur die Dateien kopiert, die Ihrem Muster entsprechen, es wird jedoch der vollständige Pfadname wie angegeben verwendet und nicht nur der nachfolgende Dateiname.
Diese Option ist jedoch nicht portierbar. Soweit ich weiß, wird sie nur von der GNU-Version von cp unterstützt.
Antwort2
Ihr Muster schließt möglicherweise die Dateien aus, die Sie nicht kopieren möchten, aber es schließt nicht die Verzeichnisse aus, die diese enthalten und die Sie angewiesen haben, cp
rekursiv zu kopieren. Die Dateien werden also trotzdem kopiert. Schlimmer noch, wenn Sie einen Quellbaum wie
foo
foo/bar.txt
hello
hello/world
hello/world/wibble.txt
Anschließend wird das Muster erweitert, foo hello hello/world hello/world/wibble.txt
sodass Sie am Ende folgende Dateien erhalten $TMPDIR
:
foo
foo/bar.txt
hello
hello/world
hello/world/wibble.txt
wibble.txt
world
world/wibble.txt
Dies hat nichts damit zu tun, dass das Muster „nicht mehr gültig“ ist. Das Muster wird von der Shell erweitert und cp
sieht nur die Liste der Dateien.
Sie müssen ein Kopiertool verwenden, das Dateien ausschließen kann, während es die rekursive Durchquerung durchführt.
Sie können hierfür zcp verwenden, es kopiert die Verzeichnisse jedoch nicht und erstellt auch keine Zielverzeichnisse automatisch. Das einfachste Tool für diese Aufgabe ist rsync. Pax ist eine weitere Option.
rsync -a --exclude='*.foo/*' --exclude='bar.txt' --exclude='*.abc' --exclude='/qux.txt' $(dirname $0) $TMPDIR