vergleich von Verzeichnissen



  • hallo,

    ich müsste ein Skript schreiben das Verzeichnisse vergleicht(vereinfachtes dircmp) und Unterschiede ausgibt. Jeweils 3 Ausgaben nach Bedingung:

    alle Filenamen, die nur in dir1 vorkommen
    alle Filenamen, die nur in dir2 vorkommen
    alle Filenamen, die in beiden Directories vorkommen, aber die Dateien unterschiedlich sind
    alle Filenamen, die in beiden Directories vorkommen, und bei denen die Dateien identisch sind

    und es hat 3 Optionen:

    -h: help, Ausgabe der Usage
    -s: silent, es werden nur Unterschiede ausgegeben (Fall 4 oben wird also nicht ausgegeben)
    -v: verbose, Dateien werden im Format "ls -l" ausgegeben.

    Ich habe mir den Quellcode von dircmp schon angesehnen, ist für mich jedoch nicht ganz nachvollziehbar. Ich weiss das ich (theoretisch) mit comp in einer Schleife die Dateien vergleichen muss, nur nicht genau wie...
    Ich habe auch gehofft das Ihr ein paar Befehle kennt die dieses vorhaben einigermaßen erleichtern oder unterstützen.


  • Mod

    Macht nicht ein gutes altes diff schon alles, was du möchtest?



  • Macht nicht ein gutes altes diff schon alles, was du möchtest?

    nein, da ich es selber schreiben muss. Also ein eigenes dirdiff sozusagen.

    Ich bin jetzt fast am ende mit meinem Skript. Ich muss wissen wie ich, wenn ich gleiche Dateien in einem Ordner gefunden habe, so ausgeben kann das es so aussieht als ob ich 'ls-l' verwendet habe nur soll es halt nicht alle sondern nur einmal die Gleichen und einmal die Unterschiedlichen anzeigen!

    Wie kriege ich dass hin? muss ich irgendwie in 'ls' pipen?

    Ich gebe die Dateien nämlich in einer Schleife einzeln nach jedem vergleich mit "echo $file" aus.



  • Schreib die Dateinamen in ein Array, und dann

    ls -l "${files[@]}"
    

    ...unter der Annahme, dass das Array files heißt.



  • Ich weiss leider nicht genau wie ich die $files in dem Array speichern kann da ich die Schleife für das Vergleichen durchlaufe wie kann ich das kombinieren?

    Hier das letzte Stück vom Code, damit Ihr versteht was ich meine:
    Es sei gesagt das dieser teil vom Code nicht funktionsfähig ist.

    # --- Vergleich & Ausgabe (Fall 3,4) ---
    if $SILENT;then
     echo "Identische Dateien in beiden Verzeichnissen:"
     cd $ldir
     for file in $(ls)
      do
       cd $rdir
       if [ ! -f $file ];then cmp -s "$rdir$file" "$ldir$file"
       if [ $? -eq 0 ];then
        if $Verbose;then 
         echo $file #ein "L"
        else
         echo $file #eine "eins"
        fi
       fi
      fi
     done
    fi
    
     echo "Unterschiedliche Dateien in beiden Verzeichnissen:"
     cd $ldir
     for file in *
      do
       cd $rdir
       if [ ! -f $file ];then cmp -s "$rdir$file" "$ldir$file"
       if [ $? -eq 1 ];then
        if $Verbose;then 
         echo $file
        else
         echo $file
        fi
       fi
      fi
     done
    

    Alternative könnte man auch:

    ls -l $ldir | while read f; do
      if [ ! -d "$ldir/$f" ];then
        echo "$f"
      fi
    done
    

    Das gibt mit ls -l aus nur weiss ich nicht wie ich hier vergleichen könnte.



  • Meine Güte, einen Blick in die Manpage könntest du ja auch mal werfen. 🙄

    Also, ich denk mir das etwa so:

    ix_equal=0
    ix_diff=0
    for f in *; do
        if cmp yadda yadda; then
          files_equal[$ix_equal]="$f"
          let ++ix_equal
        else
          files_diff[$ix_diff]="$f"
          let ++ix_diff
        fi
    done
    
    ls -ld "${files_diff[@]}"
    ls -ld "${files_equal[@]}"
    

    Du solltest dir übrigens darüber im Klaren sein, dass diese Art der Dateiauflistung (for f in 😉 Dateien ignoriert, die nur im entfernten Verzeichnis liegen und versteckte Dateien generell nicht erfasst. for i in $(ls) ist dann eine schlechte Idee, wenn Dateinamen mal Leerzeichen enthalten können.



  • Die Idee ist perfekt habe sie gleich eingebaut 😃

    Ich bin kurz davor das Skript zu ende zu bringen nur erhalte ich Fehler beim vergleich cmp findet sucht in seltsamen Verzeichnissen die es nicht geben kann.

    Bsp. cmp /home/user /home/user/bla -> /home/user/user kein solches Verzeichniss oder Datei.

    Suche den Fehler schon länger finde ihn aber nicht, das ist das vollständige Skript!

    #!/bin/bash
    #1. alle Filenamen, die nur in dir1 vorkommen
    #2. alle Filenamen, die nur in dir2 vorkommen
    #3. alle Filenamen, die in beiden Directories vorkommen, aber die #   Dateien unterschiedlich sind
    #4. alle Filenamen, die in beiden Directories vorkommen, und bei #   denen die Dateien identisch sind
    
    SCRIPTNAME=$(basename "$0")
    BADUSAGE="Falsche eingabe \"$SCRIPTNAME -h\" fuer hilfe."
    
    SILENT=true
    VERBOSE=false
    
    OPTIND=1 #Index auf Optionen
    while getopts :hsv option; do
      case "$option" in
      s) SILENT=false
      ;;
      v) VERBOSE=true
      ;;
      h)
      echo "$SCRIPTNAME -- Vergleicht Dateien in zwei Verzeichnissen."
      echo "$SCRIPTNAME [-h][-v][-s] Verzeichnis1 Verzeichnis2"
      echo " -h zeigt aktuelle hilfe"
      echo " -v fuer laengeres Listing"
      echo " -s nur unterschiede werden ausgegeben"
      exit 0
      ;;
    
      \?)
      echo "$BADUSAGE">&2
      exit 1
      ;;
    
      esac
    done
    
    shift $((OPTIND-1)) # auf Wert nach Option zeigen
    
    # --- Fehlerprüfung auf 2 Argumente und ob Verzeichnis ---
    if [ $# -ne 2 ];then
      echo "Zum vergleichen 2 Verzeichnisse noetig"
      echo "$BADUSAGE" >&2
      exit 1
    elif [ ! -d "$1" ];then
      echo "Kein Verzeichnis: $1" >&2
      echo "$BADUSAGE" >&2
      exit 1
    elif [ ! -d "$2" ];then
      echo "Kein Verzeichnis: $2" >&2
      echo "$BADUSAGE" >&2
      exit 1
    fi
    
    # --- Pfade für vergleich merken ---
    cdir=`pwd` # aktuelles Verz.
    cd "$2"
    rdir=`pwd` # VRechts
    cd "$cdir"
    cd "$1"
    ldir=`pwd` # VLinks
    
    if [ "$ldir" = "$rdir" ];then
       exit 0
    fi
    
    # --- Ausgaben (Fall 1,2) ---
    function Verbose? (){
    if $VERBOSE;then
      LS="ls -l "
    else
      LS="ls -1 "  
    fi
    }
    
    Verbose?
    echo "Verzeichnis 1:"
    $LS$ldir | while read f; do
      if [ ! -d "$ldir/$f" ];then
        echo "$f"
      fi
    done 
    
    echo -e "\n"
    echo "Verzeichnis 2:"
    $LS$rdir | while read f; do
      if [ ! -d "$rdir/$f" ];then
        echo "$f"
      fi
    done 
    
    # --- Vergleich & Ausgabe (Fall 3,4) ---
    equal=0
    diff=0
    
    for f in *; do
      if cmp -s "$ldir/$f" "$rdir/$f";then
        files_equal[$equal]="$f"
        let ++$equal
      else
        files_diff[$diff]="$f"
        let ++$diff
      fi
    done
    
    if $SILENT;then
      echo "Identische Dateien in beiden Verzeichnissen:"
      $LS$(files_equal[$@])
    fi
    
    echo "Unterschiedliche Dateien in beiden Verzeichnissen:"
    $LS$(files_diff[$@])
    
    exit 0
    


  • gast15 schrieb:

    #!/bin/bash
    
    # [...]
    
    $LS$rdir | while read f; do
      # [...]
    done
    

    Das geht schonmal sofort schief, wenn du Dateinamen mit Sonderzeichen hast, oder wenn die Ausgabe von ls nicht exakt das ist, was du dir vorstellst.

    Die Ausgabe von ls zu parsen ist in einem bash-Skript immer falsch.

    Weiter unten machst du es ja auch besser, da schreibst du for f in *. Das funktioniert, solange es nicht zu viele Dateien gibt.

    Anstelle ls würde ich find -print0 nehmen, also zum Beispiel

    find . -maxdepth 1 -print0 | while IFS= read -d '' -r file; do
      # [...]
    done
    

    Unabhängig davon könntest du mal probieren, "set -x" oben ins Skript zu schreiben. Dann siehst du, welche Befehle das Skript ausführt.


Anmelden zum Antworten