rsync copia solo sobre ciertos tipos de archivos usando la opción incluir

110

Utilizo el siguiente script bash para copiar solo archivos de cierta extensión (en este caso * .sh), sin embargo, todavía copia todos los archivos. que esta mal

desde = $ 1
a = $ 2

rsync -zarv --include = "*. sh" $ de $ a
user881480
fuente
4
Si bien no está estrictamente hablando, sugeriría citar $ from / $ to. No hacerlo puede darle resultados inesperados si los argumentos posicionales 1/2 incluyen espacios.
Kjetil Joergensen
¿Entendiste por qué tu comando no funcionaría?
Charlie Parker
@CharlieParker: ¿Tiene que usar rsync, esto se puede lograr muy bien con los componentes internos del shell?
Inian
Lo que esta pregunta y sus respuestas también carecen es cómo crear el comando si tengo directorios recursivos que quiero enviar solo un tipo de archivo. Parece que solo lo hace para el directorio de destino ...
Charlie Parker

Respuestas:

198

Creo que --includese utiliza para incluir un subconjunto de archivos que de otro modo están excluidos por --exclude, en lugar de incluir solo esos archivos. En otras palabras: tienes que pensar en incluir el significado de no excluir .

Prueba en su lugar:

rsync -zarv  --include "*/" --exclude="*" --include="*.sh" "$from" "$to"

Para rsync versión 3.0.6 o superior, el orden debe modificarse de la siguiente manera (ver comentarios):

rsync -zarv --include="*/" --include="*.sh" --exclude="*" "$from" "$to"

Agregar la -mbandera evitará crear estructuras de directorio vacías en el destino. Probado en la versión 3.1.2.

Entonces, si solo queremos archivos * .sh, tenemos que excluir todos los archivos --exclude="*", incluir todos los directorios --include="*/"e incluir todos los archivos * .sh --include="*.sh".

Puede encontrar algunos buenos ejemplos en la sección Incluir / excluir reglas de patrón de la página de manual

chepner
fuente
10
Si bien obtendrá todos los subdirectorios, si hay archivos .sh en los subdirectorios que desea sincronizar, es probable que también desee usar --include = "* /".
Kjetil Joergensen
50
Probé esto en rsync versión 3.0.7, que obtuve hace mucho tiempo de macports, y no funcionó con este orden de incluye / excluye. Esto es lo que terminó con la que trabajó para mí (adaptada para OP): rsync -zarv --include="*/" --include="*.sh" --exclude="*" "$from" "$to".
Bijou Trouvaille,
3
Intenté con rsync 3.0.9 y no funcionó. Bijou tiene razón, el orden no es correcto (primero --include=\*.shentonces --exclude=\*)
TrueY
3
Tenga en cuenta que siempre puede hacer clic en editar y sugerir una edición a la respuesta :)
Achal Dave
2
No funciona con su pedido de incluye / excluye, pero funciona con el pedido sugerido por Bijou Trouvaille
John Smith Opcional
56

La respuesta de @chepner copiará todos los subdirectorios independientemente del hecho de que contenga el archivo o no. Si necesita excluir los subdirectorios que no contienen el archivo y aún conservan la estructura del directorio, use

rsync -zarv  --prune-empty-dirs --include "*/"  --include="*.sh" --exclude="*" "$from" "$to"
Mente Errante
fuente
1
Este era un requisito para mí: "Si necesita excluir los subdirectorios que no contienen el archivo y aún conservan la estructura del directorio" +1
Juuso Ohtonen
1
No entiendo, ¿cómo supiste cuál era el orden de los --incluidos?
Charlie Parker
1
¿Cómo se crea el comando si tengo directorios recursivos que quiero enviar solo un tipo de archivo? Parece que solo lo hace para el directorio de destino.
Charlie Parker
15

Una adición más: si necesita sincronizar archivos por sus extensiones en un solo directorio (sin recursividad), debe usar una construcción como esta:

rsync -auzv --include './' --include '*.ext' --exclude '*' /source/dir/ /destination/dir/

Preste atención al punto en el primero --include. --no-rno funciona en esta construcción.

EDITAR:

¡Gracias a gbyte.co por el valioso comentario!

Serge Roussak
fuente
1
¿Cómo supiste cuál debía ser el orden de las banderas y qué debían incluir?
Charlie Parker
1
@CharlieParker, porque el rsync utiliza el includey las excludeopciones en el orden que se especificaron en. Además de esto, se detiene en la primera emparejado. Entonces, si especificamos --exclude '*'en el primer lugar en este ejemplo, rsync no hará nada. Consulte al hombre para obtener más explicaciones.
Serge Roussak
¿Me puedes explicar qué hace cada bandera? La primera bandera -- include './' dice ¿incluir todo en la ruta del directorio de origen? Luego, el siguiente `--include '.ext'` incluye el archivo específico en la ruta de origen nombrada .exty luego la exclusión dice no enviar nada más --exclude '*'. ¿Es eso correcto?
Charlie Parker
1
¿Cómo se crea el comando si tengo directorios recursivos que quiero enviar solo un tipo de archivo? Parece que solo lo hace para el directorio de destino.
Charlie Parker
1
¡Gracias por esto! Necesita --include '*.ext'y no--include '.ext'
gbyte
13

Aquí está la parte importante de la página de manual:

A medida que se crea la lista de archivos / directorios para transferir, rsync verifica cada nombre que se transferirá con la lista de patrones de inclusión / exclusión por turno, y se actúa sobre el primer patrón coincidente: si es un patrón de exclusión, entonces ese archivo es omitido si es un patrón de inclusión, entonces ese nombre de archivo no se omite; si no se encuentra un patrón coincidente, no se omite el nombre del archivo.

Para resumir:

  • No coincidir con ningún patrón significa que se copiará un archivo.
  • El algoritmo se cierra una vez que coincide cualquier patrón

Además, algo que termina con una barra es un directorio coincidente (como lo find -type dharía).

Separemos esta respuesta de arriba.

rsync -zarv  --prune-empty-dirs --include "*/"  --include="*.sh" --exclude="*" "$from" "$to"
  1. No te saltes ningún directorio
  2. No omita ningún .sharchivo
  3. Omitir todo
  4. (Implícitamente, no omita nada, pero la regla anterior evita que la regla predeterminada suceda).

Finalmente, --prune-empty-directoriesevita que la primera regla genere directorios vacíos por todas partes.

Jim Hunziker
fuente
Muchas gracias por explicarme lo que está pasando. Ahora hay muchas más posibilidades de que no olvide el comando.
MohamedEzz
3
"El algoritmo se cierra una vez que coincide cualquier patrón" : esta es la clave, y ninguna de las respuestas con calificaciones más altas lo explica con tanta claridad y anticipación como lo hizo aquí. Por supuesto, esto está en la página de manual en algún momento, y si Lo habría leído todo con atención, lo habría visto. Aún así, gracias.
TheDudeAbides
0

Si alguien busca esto ... Quería rsync solo archivos y carpetas específicos y logré hacerlo con este comando: rsync --include-from=rsync-files

Con archivos rsync:

my-dir/
my-file.txt

- /*
Pascal Polleunus
fuente
0

Escribí esta práctica función y puse mis scripts bash o ~/.bash_aliases. Probado la sincronización local en Linux con bash e awkinstalado. Funciona

selrsync(){
# selective rsync to sync only certain filetypes;
# based on: https://stackoverflow.com/a/11111793/588867
# Example: selrsync 'tsv,csv' ./source ./target --dry-run
types="$1"; shift; #accepts comma separated list of types. Must be the first argument.
includes=$(echo $types| awk  -F',' \
    'BEGIN{OFS=" ";}
    {
    for (i = 1; i <= NF; i++ ) { if (length($i) > 0) $i="--include=*."$i; } print
    }')
restargs="$@"

echo Command: rsync -avz --prune-empty-dirs --include="*/" $includes --exclude="*" "$restargs"
eval rsync -avz --prune-empty-dirs --include="*/" "$includes" --exclude="*" $restargs
}

Ventajas:

corto, útil y extensible cuando se quiere agregar más argumentos (es decir --dry-run).

Ejemplo:

selrsync 'tsv,csv' ./source ./target --dry-run
biocyberman
fuente