Forum Programmation.shell Soustraire une liste de fichier à une autre liste

Posté par  .
Étiquettes :
0
17
avr.
2012

Bonjour,

Je suis en train d'écrire un script assez simple qui consiste à synchroniser sur mon téléphone Android des dossiers de toute natures avec rsync.

Rsync n'aime pas qu'on lui dise "prends ces fichiers là et ignore les autres", il préfère qu'on lui dise "prends tout les fichiers sauf ceux là", dans le premier cas on se retrouve avec un tas de problème, donc ce qu'il faut parvenir à faire c'est de lui donner une liste de tout les fichiers qu'il ne devra pas synchroniser et non pas la liste de ceux qu'il devrait.

Donc je cherche un moyen d'obtenir une telle liste.

Je peux avoir la liste des chemins absolus de tous les fichiers d'un répertoire de façon récursive avec ls -d -1 $PWD/**/* (dans un terminal zsh, un bash normal ça marche pas), et j'ai déjà ma liste de fichier à inclure dans la synchronisation avec tout les chemins absolus.

Je suis certain qu'il existe un truc obscure à faire avec awk, sed ou grep pour parvenir à soustraire la seconde liste à la première, mais bon si c'est pas le cas, je pourrai faire autrement, mais je suis quand même curieux de savoir si c'est possible de faire ça en une seule ligne de commande plutôt que de faire des boucles et des conditions.

  • # C'est bon j'ai trouvé

    Posté par  . Évalué à 2.

    Il faut croire que j'avais mal cherché…

    Voici la solution pour ceux que ça intéresserait :

    ls -d -1 $PWD/**/* | comm -23 - <(sort liste_a_exclure.txt)

    • [^] # Re: C'est bon j'ai trouvé

      Posté par  . Évalué à 2.

      Zsh a un opérateur spécifique pour retirer des fichiers particuliers: ~

      Par exemple: print -l **/*~*.c va lister tout les fichiers, sauf les .c.

      Attention, le premier * est un opérateur de globbing et signifie « tous les fichiers d'un répertoire », mais le second * est un opérateur d'expression régulière Zsh et correspond à « n'importe quelle chaine ».

      Donc pour lister tous les fichiers et retirer uniquement les .c du répertoire courant, il faut une expression régulière qui refuse les \:
      print -l **/*.c~[^/]#.c

      Pour retirer une liste de fichiers spécifiques, il faut enchaîner les ~:
      print -l **/*.c~aaa.c~bbb.c~ccc.c

      Bien sûr, n'oubliez pas: setopt extendedglob

      • [^] # Re: C'est bon j'ai trouvé

        Posté par  . Évalué à 1.

        Merci pour ces précisions, c'est intéressant, je n'ai pas regardé le fonctionnement de zsh plus en profondeur, je viens tout juste d'en faire mon terminal par défaut

  • # Options de rsync

    Posté par  (site web personnel) . Évalué à 3.

    Dans rsync il y a des options --include et --include-from qui, si je comprends bien ton problème, font ce que tu veux. Il faut que tu lises la section FILTER RULES du manuel.

    • [^] # Re: Options de rsync

      Posté par  . Évalué à 1.

      Justement, comme je l'expliquais, ces options ne fonctionnent pas correctement.

      J'ai bien évidement essayé tout au début, ça semblait simple à mettre en place, mais on se heurte à un certain nombre de problèmes dans la pratique (impossibilité par exemple de supprimer les fichiers qui ne sont plus dans la liste par exemple plus un tas d'autres trucs obscures qui fait qu'au final c'est le bazar).

      Je crois avoir réussi à trouver une commande qui fonctionne :

      ls -d -1 -A -F "$dir"**/* | sed '/\/$/d' | sed 's|\*$||g' | sed 's|@$||g' | sed 's|\|$||g' | comm -23 - <(sort "$playlist") | sed 's|'"$dir"'|/|g' | sed 's|\[|\*|g' | sed 's|\]|\*|g' | rsync -vvvPrlitu --rsync-path="$rsync_path" --delete --delete-during --size-only --delete-excluded --exclude-from=- "$dir" -e ssh "$user@$server:"$backup_dir""

      Y'a plein de sed pour faire en sorte que ça marche (je suis obligé de supprimer les répertoires de la liste renvoyé par ls) et j'ai aussi découvert un bug, si y'a des crochets dans le nom du fichier, alors la règle d'exclusion est ignoré (c'est pour ça que je remplace les crochets par des astérisques)

      Sinon, je ne sais pas pourquoi, mais impossible de se baser sur la date des fichiers pour savoir s'il sont à jour ou pas, obligé d'utiliser --size-only (qui dans la pratique ne devrait pas être trop embêtant), et ce malgré l'utilisation de l'option --modify-window.

      • [^] # Re: Options de rsync

        Posté par  (site web personnel) . Évalué à 3.

        Y'a plein de sed pour faire en sorte que ça marche

        Y'en a trop! Deux remarques. 1. Utilise toujours le même caractère pour délimiter les patterns, ça t'évite de faire des échappements et c'est plus facile à relire. LEs caractères habituels sont /@+%= ici tu peux utiliser % qui n'apparaît pas dans tes paterns.

        j'ai aussi découvert un bug, si y'a des crochets dans le nom du fichier, alors la règle d'exclusion est ignoré

        Le bug est dans ta façon de lire la page de man. Je te sors quelques paragraphes qui vont t'intéresser (il faut que tu lises toutes la section FILTER RULES et les suivantes sur INCLUDE, EXCLUDE).

               For instance, this
               won't work:
        
                      + /some/path/this-file-will-not-be-found
                      + /file-is-included
                      - *
        
        
               This  fails  because the parent directory "some" is excluded by the '*'
               rule, so rsync  never  visits  any  of  the  files  in  the  "some"  or
               "some/path" directories.
        
        

        pour le fameux bug:

               o      rsync  chooses  between doing a simple string match and wildcard
                      matching by checking if the pattern contains one of these  three
                      wildcard characters: '*', '?', and '[' .
        
        

        et

               o      in a wildcard pattern, a backslash can be used to escape a wild-
                      card  character,  but  it is matched literally when no wildcards
                      are present.
        
        

        En relisant ces deux sections de rsync(1) tu devrais t'en sortir plus proprement.

        • [^] # Re: Options de rsync

          Posté par  . Évalué à 1.

          Y'en a trop! Deux remarques. 1. Utilise toujours le même caractère pour délimiter les patterns, ça t'évite de faire des échappements et c'est plus facile à relire. LEs caractères habituels sont /@+%= ici tu peux utiliser % qui n'apparaît pas dans tes paterns.

          Pour ce qui concerne le premier sed, je ne peux justement pas utiliser autre chose que /, c'est pour ça que j'ai utilisé | sur les autres mais pas sur celui là.

          Sinon il semblerait que la carte sd soit montée par android comme étant non sensible à la casse, du coups, ça me pose un tas de soucis (et il est finalement probable que les soucis que j'ai remarqué avec include-from viennent de là)…

          Bref je vais refaire tout mon script en utilisant des liens symboliques.

      • [^] # Re: Options de rsync

        Posté par  . Évalué à 3. Dernière modification le 19 avril 2012 à 09:33.

        je suis obligé de supprimer les répertoires de la liste renvoyé par ls

        alors utilise find

        j'ai pas testé, mais ca donnerait :

        find . -type f -exec rsync TA LISTE D'OPTION A RSYNC {} destination \;

        le -exec pour dire à find d'executer rsync … pour chaque resultat
        {} etant le resultat du find

  • # Grep

    Posté par  (site web personnel) . Évalué à 2.

    Pour soustraire une liste de fichiers FORBIDDEN aux fichiers de la liste SET, on peut tout simplement utiliser grep (mais où avais-je la tête?):

    grep -v -F -f FORBIDDEN SET
    
    

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.