2010-02-03 27 views
162

Ich versuche, ein einfaches Bash-Skript zu schreiben, das den gesamten Inhalt eines Ordners einschließlich versteckter Dateien und Ordner in einen anderen Ordner kopiert, aber bestimmte bestimmte Ordner ausschließen möchte. Wie könnte ich das erreichen?Ordner rekursiv kopieren, ausgenommen einige Ordner

+1

Ich stelle mir so etwas wie finden. -name * piped an grep/v "exclude-pattern", um diejenigen zu filtern, die nicht erwünscht sind, und piped dann an cp, um die Kopie zu erstellen. –

+1

Ich habe versucht, so etwas zu tun, aber konnte nicht herausfinden, wie man cp mit einer Pipe – trobrock

+1

verwenden Dies sollte wahrscheinlich zu super Benutzer gehen. Der Befehl, nach dem Sie suchen, ist xargs. Sie könnten auch etwas wie zwei Teer tun, die durch eine Pipe verbunden sind. –

Antwort

277

Verwendung rsync:

rsync -av --exclude='path1/to/exclude' --exclude='path2/to/exclude' source destination 

Beachten Sie, dass mit source und source/ unterschiedlich sind. Ein abschließender Schrägstrich bedeutet, den Inhalt des Ordners source in destination zu kopieren. Ohne den abschließenden Schrägstrich, kopieren Sie den Ordner source in destination. Wenn Sie viele Verzeichnisse (oder Dateien) ausschließen müssen, können Sie alternativ --exclude-from=FILE verwenden, wobei FILE der Name einer Datei ist, die Dateien oder Verzeichnisse enthält, die ausgeschlossen werden sollen.

--exclude können auch Platzhalter wie --exclude=*/.svn*

+33

note 'path1/to/exclude' usw. sind ein Unterverzeichnis von "source". – abe

+0

Wenn Sie - wie ich - eine ganze Struktur rekursiv kopieren und nur einen bestimmten Dateityp behalten möchten, können Sie auch rsync verwenden: rsync -rav --include = */--include = "*. Txt" - -exclude = * test/mytest Dadurch werden alle TXT-Dateien aus dem Quellverzeichnis übernommen und mit intakter Struktur in das Zielverzeichnis kopiert. – slott

+5

Ich schlage vor, den --dry-run hinzuzufügen, um zu prüfen, welche Dateien kopiert werden. – loretoparisi

5

Ähnlich Jeffs Idee (nicht getestet):

find . -name * -print0 | grep -v "exclude" | xargs -0 -I {} cp -a {} destination/ 
0
EXCLUDE="foo bar blah jah"                    
DEST=$1 

for i in * 
do 
    for x in $EXCLUDE 
    do 
     if [ $x != $i ]; then 
      cp -a $i $DEST 
     fi 
    done 
done 

Ungeprüfte ...

2

Sie Teer, mit --exclude Option verwenden können, und entpacken Sie es dann in Ziel.

zB
cd /source_directory 
tar cvf test.tar --exclude=dir_to_exclude * 
mv test.tar /destination 
cd /destination 
tar xvf test.tar 

finden Sie in der Manpage von Teer für weitere Informationen

32

Verwenden Teer zusammen mit einem Rohr.

Sie können diese Technik sogar über SSH verwenden.

+2

Sollte nicht ein Punkt vor dem Rohr sein? Das heißt, "tar cf - --exclude = dir_to_exclude. |" ... –

+0

Korrekt, aktualisiert. –

+0

@Kyle Butt, Wenn ich google, es heißt, dass wir tar verwenden, um eine Gruppe von Dateien in ein Archiv zu konvertieren, so wie dies für das Kopieren von Ordner funktioniert, können Sie dies erklären, ich versuche diesen Code, es funktioniert perfekt, aber ich brauche ein gutes Verständnis in diesem Befehl. – acer

7

Sie find mit der -prune Option verwenden können.

Ein Beispiel aus man find:

 
     cd /source-dir 
     find . -name .snapshot -prune -o \(\! -name *~ -print0 \)| 
     cpio -pmd0 /dest-dir 

     This command copies the contents of /source-dir to /dest-dir, but omits 
     files and directories named .snapshot (and anything in them). It also 
     omits files or directories whose name ends in ~, but not their con‐ 
     tents. The construct -prune -o \(... -print0 \) is quite common. The 
     idea here is that the expression before -prune matches things which are 
     to be pruned. However, the -prune action itself returns true, so the 
     following -o ensures that the right hand side is evaluated only for 
     those directories which didn't get pruned (the contents of the pruned 
     directories are not even visited, so their contents are irrelevant). 
     The expression on the right hand side of the -o is in parentheses only 
     for clarity. It emphasises that the -print0 action takes place only 
     for things that didn't have -prune applied to them. Because the 
     default `and' condition between tests binds more tightly than -o, this 
     is the default anyway, but the parentheses help to show what is going 
     on. 
+0

Requisiten, um ein hochrelevantes Beispiel direkt aus einer Manpage zu finden. –

0

inspiriert von @ SteveLazaridis Antwort, die hier versagen würde, ist eine Funktion POSIX-Shell - einfach kopieren und in eine Datei cpx in yout $PATH benannt und es executible machen (chmod a+x cpr). [Quelle ist jetzt in meiner GitLab verwaltet.

#!/bin/sh 

# usage: cpx [-n|--dry-run] "from_path" "to_path" "newline_separated_exclude_list" 
# limitations: only excludes from "from_path", not it's subdirectories 

cpx() { 
# run in subshell to avoid collisions 
(_CopyWithExclude "[email protected]") 
} 

_CopyWithExclude() { 
case "$1" in 
-n|--dry-run) { DryRun='echo'; shift; } ;; 
esac 

from="$1" 
to="$2" 
exclude="$3" 

$DryRun mkdir -p "$to" 

if [ -z "$exclude" ]; then 
    cp "$from" "$to" 
    return 
fi 

ls -A1 "$from" \ 
    | while IFS= read -r f; do 
    unset excluded 
    if [ -n "$exclude" ]; then 
    for x in $(printf "$exclude"); do 
     if [ "$f" = "$x" ]; then 
     excluded=1 
     break 
     fi 
    done 
    fi 
    f="${f#$from/}" 
    if [ -z "$excluded" ]; then 
    $DryRun cp -R "$f" "$to" 
    else 
    [ -n "$DryRun" ] && echo "skip '$f'" 
    fi 
done 
} 

# Do not execute if being sourced 
[ "${0#*cpx}" != "$0" ] && cpx "[email protected]" 

Anwendungsbeispiel

EXCLUDE=" 
.git 
my_secret_stuff 
" 
cpr "$HOME/my_stuff" "/media/usb" "$EXCLUDE" 
Verwandte Themen