Hinweis: Das Forum wird geschlossen! Neue Registrierungen sind nicht mehr möglich!

 Zurück zu Pro-Linux   Foren-Übersicht   FAQ     Suchen    Mitgliederliste
Bash: Dateinamen vergleichen und kopieren

 
Neuen Beitrag schreiben   Auf Beitrag antworten    Pro-Linux Foren-Übersicht -> Programmieren - Allgemein
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
rob090225
Gast





BeitragVerfasst am: 25. Feb 2009 13:27   Titel: Bash: Dateinamen vergleichen und kopieren

Hi,

bin gerade dabei mich in Linux und Bash bzw. Shell Scripting einzuarbeiten. Mit anderen Worten: ein Shell Script-Anfänger.

Ich soll ein Script schreiben, welches mit Hilfe von Übergabeparametern ein Verzeichnis auf Dateien durchsucht. Sofern im selben Verzeichnis eine Datei mit dem selben Dateinamen, aber mit anderer Dateiendung vorhanden ist, sollen die zutreffenden Dateien kopiert werden.

Konkret sieht der Scriptaufruf so aus:
./script.sh <quellverzeichnis> <zielverzeichnis> <dateiendung1> <dateiendung2>
also z.B. ./script.sh /home/test/ /home/test/archiv/ md5 tgz

Beispieldateien im Verzeichnis /home/test/:
20090220_132010_blabla.tgz
20090220_132010_blabla.md5
20090221_151050_dumdidum.tgz
20000221_151050_dumdidum.md5
(Sofern zu einer .tgz-Datei eine zugehörige .md5-Datei existiert, sollen sowohl tgz und md5 kopiert werden)

Mein bisheriger Ansatz wie folgt:

Code:

#!/bin/bash

inputDir=$1
outputDir=$2
fileExt1=$3
fileExt2=$4

var1=( `find $inputDir -name "*.$fileExt1" | sed "s/.$fileExt1//g;s/$inputDir//g"` )    # sed benutzen, um bei der Datei-Trefferliste jeweils die Dateiendung und den Pfad zu entfernen, um den Dateinamen in var1 mit var2 vergleichen zu können.
var1Num=${#var1[*]}

var2=( `find $inputDir -name "*.$fileExt1" | sed "s/.$fileExt1//g;s/$inputDir//g"` )
var2Num=${#var2[*]}

# Zählvariablen deklarieren
var1Counter=0
var2Counter=0
copyCounter=0

# Sammeln der Dateiennamen, zu denen sowohl eine .tgz- als auch .md5-Datei vorhanden ist
for ((var1Counter=0;$var1Counter<$var1Num;var1Counter++))
do
  for ((var2Counter=0;$var2Counter<$var2Num;var2Counter++))
  do
    var1=${var1[var1Counter]}
    var2=${var2[var2Counter]}
     if [ "$var1" = "$var2" ]
     then
       copyList[copyCounter]=${var1[var1Counter]}
      ((copyCounter++))
     fi
  done
done

let copyCounter=$copyCounter-1
for ((i=0;i<$copyCounter;i++))
do
  echo copyList: ${copyList[$i]}
  cp -p ${copyList[$i]}.$fileExt1 $inputDir $outputDir
  cp -p ${copyList[$i]}.$fileExt2 $inputDir $outputDir
done


So, nun wird einigen sicherlich schon ins Auge stoßen, dass ich an der Stelle
Code:
var1=( `find $inputDir -name "*.$fileExt1" | sed "s/.$fileExt1//g;s/$inputDir//g"` )
Probleme bekomme: man müsste innerhalb der Variable $inputDir bzw. Parameter $1 die Slashes maskieren.
Hier bin ich irgendwie in einer Sackgasse gelandet...

Wie könnte ich dies bewerkstelligen? Oder anders gefragt: gibt es noch eine besser/einfachere Möglichkeit den Dateinamenvergleich usw. zu bewerkstelligen?

Sry für den langen Text, aber ich wollte die Situation möglichst genau schildern Wink
 

Janka



Anmeldungsdatum: 11.02.2006
Beiträge: 3569

BeitragVerfasst am: 25. Feb 2009 15:00   Titel:

Ich würde das viel einfacher machen:
Alle Dateien finden, auf die die Maske passt, in eine Schleife abkippen. Dort gucken, ob die Partnerdatei existiert. Wenn ja, beide Dateien kopieren.
Code:

#!/bin/bash
 
inputDir=$1
outputDir=$2
fileExt1=$3
fileExt2=$4

find $inputDir -name "*.$fileExt1" | while read thisFile
do
  otherFile=$(dirname $thisFile)/$(basename $thisFile .$fileExt1).$fileExt2
  [ -f $otherFile ] && cp $thisFile $otherFile $outputDir
done

Janka
_________________
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
 
Benutzer-Profile anzeigen Private Nachricht senden

rob090225
Gast





BeitragVerfasst am: 26. Feb 2009 13:17   Titel:

Ohje, wenn ich mir diese paar Zeilen so anschaue wird mir klar, dass ich es nicht hätte umständlicher machen können.

Allerdings erschließt sich mir nicht so recht die Logik in der while-Schleife.

Nun ergibt sich auch noch die Frage:
Wie kann ich innerhalb der Dateisuche und des Kopiervorgangs (bzw. sollen die Dateien verschoben werden, nicht kopiert) Returncodes abfangen? Ich möchte folgende Returncodes nutzen:
0 -> es wurden Dateien verarbeitet
4 -> es lagen keine Dateien zuer Verarbeitung vor
8 -> Fehler: Schreibschutz auf Datei, die verschoben werden soll
12 -> Input oder Outputverzeichnis nicht gefunden, kein Speicherplatz im Outputdirectory

Bin irgendwie nicht in der Lage das in deine Schleife zu packen :/
 

Janka



Anmeldungsdatum: 11.02.2006
Beiträge: 3569

BeitragVerfasst am: 26. Feb 2009 14:56   Titel:

rob090225 hat folgendes geschrieben::
Allerdings erschließt sich mir nicht so recht die Logik in der while-Schleife.

find ... gibt eine Liste aus Dateinamen aus, auf die das Muster "*.$fileExt1" passt. Diese Liste wird von der while-Schleife zeilenweise mittels "read" gelesen. Die gelesene Zeile landet in $thisFile (z.B "20090220_132010_blabla.md5"). Daraus konstruiert otherFile=... jeweils den Namen der Partnerdatei (hier: "20090220_132010_blabla.tgz")
Im nächsten Schritt wir geguckt, ob diese Partnerdatei existiert und eine normale Datei ist [ -f $otherFile ], wenn das der Fall ist (&&) werden beide kopiert (cp ...).

Zitat:

Wie kann ich innerhalb der Dateisuche und des Kopiervorgangs (bzw. sollen die Dateien verschoben werden, nicht kopiert) Returncodes abfangen? Ich möchte folgende Returncodes nutzen:
0 -> es wurden Dateien verarbeitet
4 -> es lagen keine Dateien zuer Verarbeitung vor
8 -> Fehler: Schreibschutz auf Datei, die verschoben werden soll
12 -> Input oder Outputverzeichnis nicht gefunden, kein Speicherplatz im Outputdirectory

Irgendein Grund, genau diese Zahlen für die Returncodes zu nehmen?

Fehlerbehandlung in der Shell ist immer etwas komplizierter, weil man ja fast alles mit externen Programm macht und es daher notwendig ist, alle möglichen Fehler dieser Programme zu verarbeiten, wenn man alles abfangen will. Umgekehrt musst du dich aber auch auf die Fehlerbilder beschränken, die du eindeutig ermitteln kannst.

Deine Fehler 8 und 12 kannst du ermitteln, indem du das Ergebnis von "cp" überwachst. Deinen Fehler 4 bekommst du raus, indem du in der Schleife irgendwo eine Variable setzt, und später außerhalb prüfst, ob diese gesetzt wurde.

Im übrigen kann man auch Dateien verschieben oder löschen, die schreibgeschützt sind. Verschieben oder Löschen erfordert nämlich nur das Recht, das Directory zu ändern in dem sich der jeweilige Datei*name* befindet.

Janka
_________________
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
 
Benutzer-Profile anzeigen Private Nachricht senden

rob090225
Gast





BeitragVerfasst am: 26. Feb 2009 15:46   Titel:

Noch einmal ein dickes danke an dich, auch für die ausführliche Erklärung des Codes!

Und ja, die Returncodes müssen so verwendet werden, da diese in einem späteren Schritt von anderen, bereits vorhandenen, Scripten abgefragt und verwendet werden.

Ich kam nun auf die glorreiche Idee in die Schleife einen Counter einzubauen, um auch die Anzahl der kopierten Dateien zu erfassen:

Code:

counter=0

# Dateien einlesen, vergleichen und kopieren
find $inputDir -name "*.$fileExt1" | while read thisFile
do
  otherFile=$(dirname $thisFile)/$(basename $thisFile .$fileExt1).$fileExt2
  echo "DIRNAME: $(dirname $thisFile)"
  echo "BASENAME: $(basename $tisFile .$fileExt1)"
  echo "BASENAME: $(basename $tisFile .$fileExt1).$fileExt2"
  [ -f $otherFile ] && cp $thisFile $otherFile $outputDir
  ((counter++))
  echo "INNERHALB SCHLEIFE: $counter"
done

echo "AUSSERHALB SCHLEIFE: $counter"


Problem:
echo "INNERHALB SCHLEIFE: $counter" zeigt mir immer korrekt die Anzahl der kopierten Dateien an, echo "AUSSERHALB SCHLEIFE: $counter" jedoch nicht. Die Variable $counter hat außerhalb der Schleife immer den Wert, den ich ihr ganz zu Beginn des Programms mit counter=0 zuweise... warum? Sad
 

Janka



Anmeldungsdatum: 11.02.2006
Beiträge: 3569

BeitragVerfasst am: 26. Feb 2009 23:30   Titel:

rob090225 hat folgendes geschrieben::

Problem:
echo "INNERHALB SCHLEIFE: $counter" zeigt mir immer korrekt die Anzahl der kopierten Dateien an, echo "AUSSERHALB SCHLEIFE: $counter" jedoch nicht.

Das ist logisch, denn für jede Pipeline " | while ..." muss eine zusätzliche Shell-Instanz gestartet werden. Der Code in der Schleife wird also in einem anderen Prozess ausgeführt als der außerhalb der Schleife. Um Daten zurück nach außerhalb zu geben, musst du daher eine Hilfsdatei benutzen, oder auf die Standardausgabe schreiben und diese außen wieder einlesen.

Code:

# Dateien einlesen, vergleichen und kopieren
counter=$(find $inputDir -name "*.$fileExt1" | while read thisFile
do
  otherFile=$(dirname $thisFile)/$(basename $thisFile .$fileExt1).$fileExt2
  echo >&2 "DIRNAME: $(dirname $thisFile)"
  echo >&2 "BASENAME: $(basename $tisFile .$fileExt1)"
  echo >&2 "BASENAME: $(basename $tisFile .$fileExt1).$fileExt2"
  [ -f $otherFile ] && cp $thisFile $otherFile $outputDir
  printf "x"
done | wc -c)

echo >&2 "AUSSERHALB SCHLEIFE: $counter"

>&2 gibt auf die Standardfehlerausgabe aus. Nützlich für Debugzwecke. printf hat gegenüber echo den Vorteil, dass man die Ausgabe besser formatieren kann. Unter anderem gibt es ohne Auftrag kein \n aus. "wc -c" zählt die Anzahl der Zeichen ("x"se), die in der Schleife ausgegeben wurden. Dies entspricht der Zahl der Schleifendurchläufe und somit der Dateien.

Shellprogrammierung ist halt oft mal etwas durch die Brust ins Auge...

Janka
_________________
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
 
Benutzer-Profile anzeigen Private Nachricht senden

Beiträge vom vorherigen Thema anzeigen:   
     Pro-Linux Foren-Übersicht -> Programmieren - Allgemein Alle Zeiten sind GMT + 1 Stunde
Seite 1 von 1

 
Gehen Sie zu:  

Powered by phpBB © phpBB Group
pro_linux Theme © 2004 by Mandaxy