2010-02-03 16 views
162

Sto provando a scrivere un semplice script bash che copierà l'intero contenuto di una cartella, inclusi file e cartelle nascosti in un'altra cartella, ma voglio escludere determinate cartelle specifiche. Come potrei ottenere questo?Copia cartella in modo ricorsivo, escluso alcune cartelle

+1

immagino qualcosa come find. -name * convogliato a grep/v "exclude-pattern" per filtrare quelli che non si desidera e quindi inviati a cp per eseguire la copia. –

+1

Stavo cercando di fare qualcosa del genere, ma non riuscivo a capire come usare cp con una pipe – trobrock

+1

Questo dovrebbe probabilmente andare a super utente. Il comando che stai cercando è xargs. Potresti anche fare qualcosa come due tar collegati da una pipe. –

risposta

277

Usa rsync:

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

noti che l'utilizzo source e source/ sono diversi. Una barra finale significa copiare il contenuto della cartella source in destination. Senza la barra finale, significa copiare la cartella source in destination.

In alternativa, se si dispone di molte directory (o file) da escludere, è possibile utilizzare --exclude-from=FILE, dove FILE è il nome di un file contenente file o directory da escludere.

--exclude possono contenere anche caratteri jolly, come ad esempio --exclude=*/.svn*

+33

note 'path1/to/exclude' ecc sono una sottodirectory di "source". – abe

+0

Se tu - come me - vuoi copiare ricorsivamente un'intera struttura e mantenere solo un certo tipo di file, puoi anche usare rsync: rsync -rav --include = */--include = "*. Txt" - -exclude = * test/mytest Questo prenderà tutti i file .txt dalla directory di origine e li copierà nella directory di destinazione con la struttura intatta. – slott

+5

Suggerisco di aggiungere --dry-run per verificare quali file verranno copiati. – loretoparisi

5

Simile a un'idea di Jeff (non testata):

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 

testato ...

2

è possibile utilizzare tar, con l'opzione --exclude, e poi scompattarlo nelle più strette. ad esempio

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

vedere la pagina man di tar per ulteriori informazioni

32

Utilizzare tar insieme a un tubo.

cd /source_directory 
tar cf - --exclude=dir_to_exclude . | (cd /destination && tar xvf -) 

È possibile utilizzare questa tecnica anche su SSH.

+2

Non dovrebbe esserci un punto prima del tubo? Cioè, "tar cf - --exclude = dir_to_exclude. |" ... –

+0

Corretto, aggiornato. –

+0

@Kyle Butt, quando google, si dice che usiamo tar per convertire un gruppo di file in un archivio, quindi come funziona per copiare la cartella, puoi spiegare questo, provo questo codice, funziona perfettamente, ma io bisogno di una buona comprensione in questo comando. – acer

7

È possibile utilizzare find con l'opzione -prune.

Un esempio dal 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

Puntelli per localizzare un esempio molto rilevante direttamente da una pagina di manuale. –

0

ispirato @ di SteveLazaridis risposta, che sarebbe fallire, ecco un funzione di shell POSIX - basta copiare e incollare in un file chiamato cpx in yout $PATH e farlo executible (chmod a+x cpr). [La fonte viene ora mantenuta nel mio GitLab.

#!/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]" 

Esempio di utilizzo

EXCLUDE=" 
.git 
my_secret_stuff 
" 
cpr "$HOME/my_stuff" "/media/usb" "$EXCLUDE" 
Problemi correlati