Filtro Rsync: copiar solo un patrón


128

Estoy tratando de crear un directorio que albergue todos y solo mis archivos PDF compilados desde LaTeX. Me gusta mantener cada proyecto en una carpeta separada, todo alojado en una carpeta grande llamada LaTeX. Entonces intenté correr:

rsync -avn *.pdf ~/LaTeX/ ~/Output/

que debería encontrar todos los archivos PDF ~/LaTeX/y transferirlos a la carpeta de salida. Esto no funciona Me dice que no se encontraron coincidencias para " *.pdf". Si omito este filtro, el comando enumera todos los archivos en todas las carpetas del proyecto en LaTeX. Entonces es un problema con el filtro * .pdf. Traté de reemplazar ~/con la ruta completa a mi directorio de inicio, pero eso no tuvo ningún efecto.

Estoy usando zsh. Intenté hacer lo mismo en bash e incluso con el filtro que enumeraba cada archivo en cada subdirectorio ... ¿Qué está pasando aquí?

¿Por qué rsync no comprende mi filtro de solo PDF?


OKAY. Así que actualiza: no, lo estoy intentando

rsync -avn --include="*/" --include="*.pdf" LaTeX/ Output/

Y esto me da la lista completa de archivos. Supongo que porque todo coincide con el primer patrón ...


eh, parece que tienes razón ... Creo que mi respuesta (usando el **patrón de zsh ) debería funcionar, sin embargo.
Marcel Stimberg

Respuestas:


248

TL, DR:

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Rsync copia las fuentes en el destino. Si pasa *.pdfcomo fuentes, el shell expande esto a la lista de archivos con la .pdfextensión en el directorio actual. No ocurre un recorrido recursivo porque no pasó ningún directorio como fuente.

Por lo tanto, debe ejecutar rsync -a ~/LaTeX/ ~/Output/, pero con un filtro para indicarle a rsync que .pdfsolo copie archivos. Las reglas de filtro de Rsync pueden parecer desalentadoras cuando lee el manual, pero puede construir muchos ejemplos con solo unas pocas reglas simples.

  • Inclusiones y exclusiones:

    • Exclusión de archivos por nombre o por ubicación es fácil: --exclude=*~, --exclude=/some/relative/location(en relación con el argumento de origen, por ejemplo, se incluyen las siguientes ~/LaTeX/some/relative/location).
    • Si solo desea hacer coincidir algunos archivos o ubicaciones, inclúyalos, incluya todos los directorios que conduzcan a ellos (por ejemplo, con --include=*/) y luego excluya el resto con --exclude='*'. Esto es porque:
    • Si excluye un directorio, esto excluye todo lo que está debajo de él. Los archivos excluidos no serán considerados en absoluto.
    • Si incluye un directorio, esto no incluye automáticamente su contenido. En versiones recientes, --include='directory/***'lo haremos.
    • Para cada archivo, se aplica la primera regla de coincidencia (y se incluye todo lo que nunca coincida).
  • Patrones:

    • Si un patrón no contiene un /, se aplica al nombre del archivo sin directorio.
    • Si un patrón termina con /, se aplica solo a los directorios.
    • Si un patrón comienza con /, se aplica a toda la ruta desde el directorio que se pasó como argumento a rsync.
    • *cualquier subcadena de un solo componente de directorio (es decir, nunca coincide /); **coincide con cualquier subcadena de ruta.
  • Si un argumento fuente termina con a /, su contenido se copia ( rsync -r a/ bcrea b/foopara cada a/foo). De lo contrario, el directorio en sí se copia ( rsync -r a bcrea b/a).


Por lo tanto, aquí debemos incluir *.pdf, incluir directorios que los contengan y excluir todo lo demás.

rsync -a --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Tenga en cuenta que esto copia todos los directorios, incluso los que no contienen ningún archivo coincidente o subdirectorio que contenga uno. Esto se puede evitar con la --prune-empty-dirsopción (no es una solución universal, ya que no puede copiar un directorio ni siquiera haciendo coincidirlo explícitamente, pero ese es un requisito poco frecuente).

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

En contraste con mi solución (usando el **patrón de zsh ), esto recrea la estructura del directorio en el directorio de destino. No estoy seguro de si esto es lo que quiere el OP ...
Marcel Stimberg

Quiero incluir solo un directorio y excluir el resto de todos los directorios en el /etc/lsyncd/lsyncd.conf.luaarchivo. ¿Tienes alguna idea?
Dhaduk Mitesh

@DhadukMitesh No estoy familiarizado con lsyncd. Deberías hacer esto como una nueva pregunta.
Gilles

25
rsync -av --include="*/" --include="*.pdf" --exclude="*" ~/Latex/ ~/Output/ --dry-run

El valor predeterminado es incluir todo, por lo que debe excluir explícitamente todo después de incluir los archivos que desea transferir. Elimine --dry-run para transferir realmente los archivos.

Si comienzas con:

--exclude '*' --include '*.pdf'

Entonces la coincidencia codiciosa excluirá todo de inmediato.

Si intentas:

--include '*.pdf' --exclude '*' 

Luego, solo se transferirán los archivos pdf en la carpeta de nivel superior. No seguirá ningún directorio, ya que están excluidos por '*'.


2
A partir del 2014-03-17, esta es la mejor respuesta, ya que resuelve la pregunta original de los carteles exactamente . ¡Por favor vota! Si agrega --prune-empty-dirs(o acceso directo -m), incluso se ahorra muchos directorios vacíos en el destino, excepto que, por supuesto, los quiere como recordatorio o plan estructural.
porg

1
La mejor respuesta, --include = "* /" es la clave.
Martin Konicek

Quiero incluir solo un directorio y excluir el resto de todos los directorios en el /etc/lsyncd/lsyncd.conf.luaarchivo. ¿Tienes alguna idea?
Dhaduk Mitesh

15

Si usa un patrón como *.pdf, el shell "expande" ese patrón, es decir, reemplaza el patrón con todas las coincidencias en el directorio actual. El comando que está ejecutando (en este caso rsync) desconoce el hecho de que intentó usar un patrón.

Sin embargo, cuando usa zsh , hay una solución fácil: el **patrón se puede usar para unir carpetas de forma recursiva. Prueba esto:

rsync -avn ~/LaTeX/**/*.pdf ~/Output/

¿No copiaría todos los archivos PDF desde algún lugar dentro del directorio actual y todo desde ~ / LaTeX / a ~ / Output?
SamB

Supongo que querías decir rsync -avn ~/LaTeX/**/*.pdf ~/Output, pero la solución con --includees más escalable de todos modos.
Adam Byrtek

Lo siento, corrigió el comando que escribí mal ... Estoy de acuerdo en que el comando de inclusión (en la versión de SamB) es mejor, aunque es un poco más complicado y específico para rsync, aunque también **puede ser útil en otras situaciones.
Marcel Stimberg

1
Bash 4 ha adoptado la misma característica. Ah, y no necesita rsync aquí, cp lo hará. En algunos sistemas, si hay muchos archivos, es útil cd ~/Latex && cp -p **/*.pdf ~/Outputevitar un error de "línea de comando demasiado larga".
Gilles

1
Tenga en cuenta que los patrones de rsync utilizados en los filtros de inclusión y exclusión también tienen un ** que hace lo mismo. Puede escapar * de otras conchas poniéndolas entre comillas.
Dan Pritts

13

Puede usar finduna lista intermedia de archivos ( files_to_copy) para resolver su problema. Asegúrese de estar en su directorio personal, luego:

find LaTeX/ -type f -a -iname "*.pdf" > files_to_copy && rsync -avn --files-from=files_to_copy ~/ ~/Output/ && rm files_to_copy

Probado con Bash.


Creo que find es la solución más sólida, pero optaría por usar la -execopción find o usar xargs. Algo así como:find LaTeX/ -type f -iname "*.pdf" -print0 | xargs -0 -i rsync -avn {} Output/
Steven D

Sí ... sugeriría encontrar también ... aunque imagino que rsync debe poder hacer esto.
Gabe.

Esta es una buena solución para un problema más difícil también: presumiblemente podría usar esto para excluir archivos cuya clase de documento es standaloneo que no tienen un .texarchivo con el mismo nombre, ya que estas serán imágenes incluidas en algún documento ...
Seamus

2
La opción rsync --files-fromacepta la lectura de stdin. Esto funcionaría find LaTeX/ -type f -a -iname "*.pdf" | rsync -avn --files-from=- ~/ ~/Output/
Juan Calero

9

A juzgar por la sección "REGLAS DE INCLUIR / EXCLUIR PATRÓN" de la página de manual , la forma de hacerlo es

rsync -avn --include="*/" --include="*.pdf" ~/Latex/ ~/Output/

La diferencia crítica entre esto y la respuesta de kbrd es la --include="*/"bandera, que le dice a rsync que continúe y copie los directorios que encuentre, como se llamen. Esto es necesario porque rsync no se repetirá en un subdirectorio a menos que se le indique que copie ese subdirectorio.

Además, tenga en cuenta que las comillas evitan que el shell intente expandir los patrones a los nombres de archivos en relación con el directorio actual y realice una de las siguientes acciones:

  1. Tener éxito y estropear su filtro (no es muy probable que esté en medio de una bandera como esa, aunque realmente nunca se sabe cuándo alguien creará un archivo llamado --include=foo.pdf...)

  2. Fallando, y potencialmente produciendo un error en lugar de ejecutar el comando (como descubrió que zsh lo hace por defecto).


Entonces, esto copiará solo los PDF y la estructura del directorio, mientras que kbrd copiará los archivos, pero ignorará la estructura.
Seamus

1
Hmm Esto en realidad todavía parece intentar copiar todo, supongo porque eso es lo que hace sin el filtro, por lo que includeagregar cosas adicionales que ya están allí no cambia nada. Si ves a lo que me refiero ...
Seamus

77
Necesitas --exclude="*"después del --include="*.pdf", o esto transferirá todo.
jmanning2k

@ jmanning2k: Ah. ¡Bueno saber!
SamB

4

Qué tal esto:

rsync -avn --include="*.pdf" ~/Latex/ ~/Output/

No, man rsynccoloca el filtro después de las opciones y antes de la fuente / destino. Intenté esto y no funcionó
Seamus

Tu camino encuentra archivos .pdf en la carpeta actual, pero no de forma recursiva, como quiero. (la aopción es para archivo y, entre otras cosas, hace que la copia sea recursiva.
Seamus

1
Uy, mi mal. Actualicé mi respuesta.
kbyrd

+1 por estar tan cerca y darme una pista sobre cómo encontrar el material relevante en la página del manual. (Con suerte, incluso lo hice bien. :-)
SamB

3

Aquí hay algo que debería funcionar sin usar find. La diferencia con las respuestas ya publicadas es el orden de las reglas de filtro. Las reglas de filtro en un comando rsync funcionan de manera muy parecida a las reglas de iptable, la primera regla que coincide con un archivo es la que se usa. Desde la página del manual :

A medida que se construye la lista de archivos / directorios para transferir, rsync verifica cada nombre que se transferirá con la lista de patrones de inclusión / exclusión a su vez, 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, ese nombre de archivo no se omite; Si no se encuentra un patrón coincidente, no se omite el nombre de archivo.

Por lo tanto, necesita un comando de la siguiente manera:

rsync -avn --include="**.pdf" --exclude="*" ~/LaTeX/ ~/Output/

Tenga en cuenta el patrón "**. Pdf". Según la página del manual :

si el patrón contiene un / (sin contar un / final) o un "**", se compara con el nombre de ruta completo, incluidos los directorios iniciales. Si el patrón no contiene un "**", entonces solo se compara con el componente final del nombre de archivo. (Recuerde que el algoritmo se aplica de forma recursiva, por lo que "nombre de archivo completo" en realidad puede ser cualquier parte de una ruta desde el directorio inicial hacia abajo

En mi pequeña prueba, esto funciona recursivamente en el árbol de directorios y solo selecciona los archivos PDF.


¿Cómo lo hiciste exactamente? Según mi comprensión de la documentación y mi verificación experimental, su comando solo debe copiarse *.pdfen el directorio de nivel superior (pero no ~/LaTeX/foo/bar.pdf).
Gilles

@Gilles Crud. Tienes razón. Juré que probé esto y funcionó, pero parece que no puedo recrearlo. Y ahora que realmente leí la página del manual que cité, tiene sentido que no funcione. Queja.
Steven D

1
Bueno, descubrí dónde estaba mal mi examen. Mi "pequeña prueba" fue en un directorio que tiene mis propios archivos .tex y .pdf. Luego creé un subdirectorio "test" y un test.pdf y test.tex en ese subdirectorio. Sin embargo, no noté que había un test.pdf en mi directorio de nivel superior, probablemente debido a algún experimento rápido de LaTeX que hice.
Steven D

Todavía no entiendo el **. Sería bueno tener un ejemplo de ello. ;)
buhtz

2

Esta es mi solución preferida:

find source_dir -iname '*.jpg' -print0 |  rsync -0 -v --files-from=- . destination_dir/

El findcomando es más fácil de entender que las reglas de inclusión / exclusión de rsync:-)

Si desea copiar solo archivos PDF, simplemente cambie .jpga.pdf

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.