it-swarm-es.tech

Filtro Rsync: copiar solo un patrón

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 en ~/LaTeX/ y transfiérelos 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. Por lo tanto, es un problema con el filtro * .pdf. Intenté reemplazar ~/ con la ruta completa a mi directorio de inicio, pero eso no tuvo 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 ...

142
Seamus

TL, DR:

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

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

Entonces necesitas ejecutar rsync -a ~/LaTeX/ ~/Output/, pero con un filtro para indicarle a rsync que copie .pdf solo 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:

    • Excluir archivos por nombre o por ubicación es fácil: --exclude=*~, --exclude=/some/relative/location (en relación con el argumento fuente, por ejemplo, esto excluye ~/LaTeX/some/relative/location).
    • Si solo desea hacer coincidir algunos archivos o ubicaciones, inclúyalos, incluya todos los directorios que conducen a ellos (por ejemplo con --include=*/), 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 haré.
    • 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 de 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 con /); ** coincide con cualquier subcadena de ruta.
  • Si un argumento fuente termina con un /, su contenido se copia (rsync -r a/ b crea b/foo para cada a/foo). De lo contrario, el directorio en sí se copia (rsync -r a b crea b/a).


Por lo tanto, aquí debemos incluir *.pdf, incluya directorios que los contengan y excluya 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 archivos coincidentes o subdirectorios que contengan uno. Esto se puede evitar con el --Prune-empty-dirs opción (no es una solución universal, ya que no puede copiar un directorio incluso haciendo coincidirlo explícitamente, pero ese es un requisito poco frecuente).

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/
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 incluidos 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 '*'.

30
jmanning2k

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ó utilizar un patrón.

Sin embargo, cuando usa zsh, hay una solución fácil: El ** patrón se puede utilizar para hacer coincidir carpetas de forma recursiva. Prueba esto:

rsync -avn ~/LaTeX/**/*.pdf ~/Output/
15
Marcel Stimberg

Puede usar find y una 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.

13
Derek Frye

A juzgar por la sección "INCLUIR/EXCLUIR REGLAS DE PATRÓN" de página del 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="*/" flag, que le dice a rsync que continúe y copie los directorios que encuentre, sean cuales sean sus nombres. 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 archivo 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 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).

9
SamB

Esta es mi solución preferida:

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

El comando find 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 .jpg a .pdf

3
guettli

Qué tal esto:

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

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 similar a las reglas iptable, la primera regla que coincide con un archivo es la que se usa. Desde el página del 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 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". De acuerdo con 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/o un "**", solo se compara con el componente final del nombre de archivo. (Recuerde que el algoritmo se aplica de forma recursiva, por lo que el "nombre de archivo completo" 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.

2
Steven D

Para generar un directorio que contenga solo encabezados (../include) desde el directorio de origen:

rsync -avh --Prune-empty-dirs --exclude="build" --include="*/" --include="*.h" --exclude="*" ./* ../include/

Esto excluye todos los directorios vacíos y el directorio build

0
SCG82