2010-02-03 27 views
162

Estoy tratando de escribir un script bash simple que copiará todo el contenido de una carpeta incluyendo archivos y carpetas ocultos en otra carpeta, pero quiero excluir ciertas carpetas específicas. ¿Cómo podría lograr esto?Copiar carpeta recursivamente, excluyendo algunas carpetas

+1

me imagino algo así como hallazgo. -name * canalizado a grep/v "exclude-pattern" para filtrar los que no desea y luego canaliza a cp para hacer la copia. –

+1

Estaba tratando de hacer algo así, pero no pude entender cómo usar cp con una tubería – trobrock

+1

Esto probablemente debería ir a un súper usuario. El comando que estás buscando es xargs. También podría hacer algo así como dos alquitrán conectados por una tubería. –

Respuesta

277

uso rsync:

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

cuenta que el uso source y source/ son diferentes. Una barra inclinada significa copiar el contenido de la carpeta source en destination. Sin la barra al final, significa copiar la carpeta source en destination.

Alternativamente, si tiene muchos directorios (o archivos) para excluir, puede usar --exclude-from=FILE, donde FILE es el nombre de un archivo que contiene archivos o directorios para excluir.

--exclude también pueden contener comodines, como --exclude=*/.svn*

+33

note 'path1/to/exclude' etc. son un subdirectorio de "fuente". – abe

+0

Si usted, como yo, desea copiar recursivamente una estructura completa y solo conservar un cierto tipo de archivos, también puede usar rsync: rsync -rav --include = */--include = "* .txt" - -exclude = * test/mytest Esto tomará todos los archivos .txt del directorio de origen y los copiará al directorio de destino con la estructura intacta. – slott

+5

Sugiero agregar el --dry-run para verificar qué archivos se van a copiar. – loretoparisi

5

Similar a la idea de Jeff (no probado):

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 

No comprobado ...

2

puede utilizar el alquitrán, con la opción --exclude, y luego descomprimirlo en destino. por ejemplo

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

ver la página del manual de alquitrán para obtener más información

32

uso de alquitrán junto con un tubo.

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

Incluso puede utilizar esta técnica en ssh.

+2

¿No debería haber un punto antes de la tubería? Es decir, "tar cf - --exclude = dir_to_exclude. |" ... –

+0

Correcto, actualizado. –

+0

@Kyle Butt, cuando googleo, digo que usamos tar para convertir un grupo de archivos en un archivo, entonces, ¿cómo funciona esto para copiar la carpeta? ¿Puedes explicarlo? Intento este código, funciona perfectamente, pero necesito un buen entendimiento en este comando. – acer

7

Puede utilizar find con la opción -prune.

Un ejemplo de 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

Apoyos para localizar un ejemplo muy relevante directamente desde una página de manual. –

0

inspirado por la respuesta de @ SteveLazaridis, que fracasaría, aquí es una función de shell POSIX - sólo copiar y pegar en un archivo denominado cpx en yout $PATH y hacer que executible (chmod a+x cpr). [La fuente ahora se mantiene en mi 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]" 

Ejemplo de uso

EXCLUDE=" 
.git 
my_secret_stuff 
" 
cpr "$HOME/my_stuff" "/media/usb" "$EXCLUDE" 
Cuestiones relacionadas