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 sindund 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.
-
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.