ghost-in-the-shell
Goto Top

Datei suchen und nur Datinamen der neusten kopieren

Hi,
also ich bin noch ganz neu hier und stehe schon für mich vor einem großen Problem.
Also es geht darum.
ich möchte das ich eine batch starte und dann dort etwas eingebe. das was ich eingegeben habe, soll dann auf den Laufwerken W: und X: gesucht werden und noch mit dem zusatz"*.txt" versehen werden, so dass alle txt dateien gesucht werden welche mit aaa beginnen.
Danach soll mir der Dateiname der Datei mit dem neusten Speicherdatum ohne das ".txt" in die Zwischenablage kopiert werden.

Also auf meinem Laufwerk sind sagen wir die Dateien:
aaa.txt
aaa_1.txt
aaa_2.txt
aaa_3.txt
aaa_4.txt
aaa_5.txt
bbb.txt
bbb_1.txt
ccc.txt
ccc_1.txt
ccc_2.txt
Dies kann bis zu _99 oder noch höher hochgehen.

also wenn ich aaa eingebe, dann soll er mir praktisch "aaa_5" in die zwischenablage kopieren, weil dies die neuste datei ist.

Im Windows explorer ist dies ganz simpel.
ich würde auf suchen gehen.
als Laufwerke würde ich W: und X: auswählen
als suchwort würde ich einfach "aaa*.txt" einegebn
dann bekomme ich alle Dateien.
Dann würde ich sie nach Datum sortieren und dann von der obersten den Dateinamen ohne das ".txt" kopieren.
Das ist eigentlich schon alles.

Das funktioniert im Explorer per Hand echt super, aber ich dachte mir, dass müsste doch auch per batch möglich sein.

Content-Key: 74418

Url: https://administrator.de/contentid/74418

Ausgedruckt am: 29.03.2024 um 10:03 Uhr

Mitglied: Biber
Biber 25.11.2007 um 14:00:29 Uhr
Goto Top
Moin Michael587,

willkommen im Forum.

Realisieren lässt sich der Plan natürlich, aber ganz verstehe ich ihn nicht.
  • der Part mit dem Laufwerke W: und X: nach der jüngsten "SoUndSo"-Datei durchsuchen ist klar und ist auch eine typische Batch-Aufgabe.
  • was ich nicht verstehe I: "wenn ich den Batch starte..." : Wie? Wo? Kontextmenü Explorer? Doppelklick Desktop? Isoliert? Teil eines Gesamt-Prozesses?
  • was ich nicht verstehe II: WTF willst Du mit dem "Dateinamen" ohne Pfad/Laufwerksangabe und Endung in der Zwischenablage?????

Soll nicht heißen, dass ich nicht helfen will, aber Sinn sollte es schon machen...

Grüße
Biber
Mitglied: Biber
Biber 25.11.2007 um 15:00:38 Uhr
Goto Top
Moin MichaelS87,

ein bisschen mehr habe ich verstanden, aber noch nicht alles:

  • wieso können denn die Messreihendatei entweder irgendwo auf W: oder irgendwo auf X: sein?
  • sind die nicht immer in einem bestimmten Pfad? Oder haben W: und X gar keine Unterverzeichnisstruktur?
  • und Du brauchst nicht nur den Datei-Namen (ohne Endung), sondern auch minimal Laufwerk oder sogar Laufwerk/Pfad, richtig?

Sorry für die vielen Rückfragen, aber Bätche funktionieren eben so, dass man/frau vorher alles wissen muss... face-wink

Grüße
Biber
Mitglied: Biber
Biber 25.11.2007 um 15:47:09 Uhr
Goto Top
Moin MichaelS87,

bastla hat vorgestern eine Lösung gepostet, die schon fast genau passt. Siehe spezielle Directories mit last modified auflisten.

Die Skizze aus diesem Beitrag:
@echo off & setlocal
echo.>%temp%\whatever.xyz
for /d %%A in (D:\Backup\*_EXT) do for /f "tokens=1,2,3 delims=. " %%I in ('echo %%~tA') do echo %%K\%%J\%%I %%A >>%temp%\whatever.xyz  
sort %temp%\whatever.xyz
... diese Skizze müsstest Du nur noch ändern, so dass statt EIN Pfad ("D:\Backup\*_Ext") jetzt zwei FOR-Anweisungen nacheinander ausgeführt werden.
Einmal auf "W:\DeinMessreihenPfad\%suchname%.txt" und einmal auf "X:\DeinesKollegenMessreihenpfad\%suchname%.txt."

Den Suchnamen fragst Du am Anfang ab mit
Set /P Suchname="Bitte Dateinamensmuster für die Suche eingeben: "

Statt "sort %temp%\whatever.xyz" kannst Du schreiben:
for /f "tokens=1,2*" %%i in ('sort /R %temp%\whatever.xyz') do Set "NewestName=%%~nj"
Dann hast Du den neuesten Namen in %NewestName%

Das Senden an die Zwischenablage geht leider nur mit Zusatztools.
Eines davon heißt CLIP.exe, stammt vom sympathischen Weltmarktführer höchstselbst (in einem der ResKits, glaub ich) und sendet einen Text an das ClipBoard.

P.S. Ich bin etwas zögerlich mit der Batch-Variante, weil... sinnvoller scheint mir, das alles im Excel-Makro selbst abzufackeln.
Oder dürft ihr den nicht ändern (Kaufprogramm)??

Grüße
Biber
Mitglied: miniversum
miniversum 25.11.2007 um 17:59:37 Uhr
Goto Top
ich habe mir schon ein makro geschrieben in excel, das automatisch die benötigten werte aus diesen txt dateien hohlt, wenn ich aaa oder bbb eingebe.
Mal ne ganz doofe Frage:
Warum machst du den dann überhaubt den Sprung mit Batch und vba (vom Makro)? Erweitere doch das Makro um die Suchfunktion dann brauchst du mit dem copy&past vom Dateinamen nicht rummachen sondern nur einfach das Makro ausführen?

miniversum
Mitglied: miniversum
miniversum 25.11.2007 um 21:57:04 Uhr
Goto Top
prinzipiell geht in excelmakros das alles was auch in vbs geht.
Mitglied: bastla
bastla 25.11.2007 um 22:09:26 Uhr
Goto Top
Hallo MichaelS87!

Vielleicht kannst Du ja den folgenden Code Deinen Bedürfnissen anpassen:
Dim Suchmaske As String, Ext As String, SuchLen As Integer
Dim Zuletzt As Date, Erg As String
Dim fso As Object
Dim Ordner As Object, Datei As Object, Dateien As Object, Unter As Object

Sub Suchen()
Ext = "txt" 'Typ der zu suchenden Datei  
Roots = Array("W:\", "X:\") 'Ordner für Beginn der Suche auf den jeweiligen Laufwerken  
'Eingabe Suchmaske  
Suchmaske = InputBox("Bitte Anfang des Dateinamens als Suchmaske angeben!", "Suchmaske")  

'Hilfsvariable  
Suchmaske = LCase(Suchmaske)
SuchLen = Len(Suchmaske)
Ext = LCase(Ext)

Set fso = CreateObject("Scripting.FileSystemObject")  

Zuletzt = 0 'Initialisierung Zwischenspeicher für jüngstes Dateidatum  
Erg = ""  

For Each Root In Roots
    Set Ordner = fso.GetFolder(Root) 'Start der Suche mit dem jeweiligem Startordner je Laufwerk  
    SearchInFolder Ordner
Next

If Erg <> "" Then  
    'Voller Pfad der jüngsten passenden Datei steht in Erg  
    Workbooks.Open (Erg)
Else '... oder auch nicht.  
    MsgBox "Keine zur Suchmaske " & Chr(34) & Suchmaske & "*." & Ext & Chr(34) & _  
        " passende Datei gefunden!", vbCritical, "Datei nicht gefunden!"  
End If
End Sub

Sub SearchInFolder(Ordner)
Set Dateien = Ordner.Files
' Alle Dateien in diesem Ordner abklappern  
For Each Datei In Dateien
    'Dateityp prüfen  
    If LCase(fso.GetExtensionName(Datei.Name)) = Ext Then
        'Beginnt Dateiname mit Suchmaske?  
        If LCase(Left(Datei.Name, SuchLen)) = Suchmaske Then
            'Änderungsdatum vergleichen ...  
            If Datei.DateLastModified > Zuletzt Then
                '... und wenn neuer, speichern;  
                Zuletzt = Datei.DateLastModified
                Erg = Datei.Path 'Dateipfad natürlich auch ;-)  
            End If
        End If
    End If
Next

'Unterordner abklappern, SearchInFolder rekursiv aufrufen  
For Each Unter In Ordner.SubFolders
    SearchInFolder Unter
Next
End Sub
Bitte zu beachten, dass die Variablendeklaration der Einfachheit halber im Deklarationsteil des Moduls (vor dem ersten Sub) erfolgt - so stehen diese Variablen ohne Übergabe als Parameter auch im Sub "SearchInFolder" zur Verfügung.

Das Ermitteln der Länge des Suchstrings und das Umwandeln der Suchmaske bzw der Extension in Kleinbuchstaben als Hilfsvariable bereits vor der Such-Schleife sollte (leicht) die Performance verbessern.

Grüße
bastla
Mitglied: bastla
bastla 26.11.2007 um 13:53:31 Uhr
Goto Top
Hallo MichaelS87!

Wenn es tatsächlich genügt, nach dem Änderungsdatum des Ordners zu sortieren, sollte sich das dann nicht ganz so hinziehen. Der Code dafür sähe etwa so aus:
Dim Suchmaske As String, Ext As String, SuchLen As Integer
Dim Zuletzt As Date, Erg As String
Dim fso As Object
Dim Ordner As Object, UO As Object, As Object, Unter As Object

Sub SuchenOrdner()

Roots = Array("W:\", "X:\") 'Ordner für Beginn der Suche auf den jeweiligen Laufwerken  
'Eingabe Suchmaske  
Suchmaske = InputBox("Bitte Anfang des Ordnernamens angeben!", "Suchmaske")  

'Hilfsvariable  
Suchmaske = LCase(Suchmaske)
SuchLen = Len(Suchmaske)

Set fso = CreateObject("Scripting.FileSystemObject")  

Zuletzt = 0
Erg = ""  

For Each Root In Roots
    Set Ordner = fso.GetFolder(Root) 'Start der Suche  
    SearchInFolder Ordner
Next

If Erg <> "" Then  
    'Voller Pfad der jüngsten passenden Ordners steht in Erg  
    Worksheets("Tabelle1").Range("A1").Value = Erg  
Else '... oder auch nicht.  
    MsgBox "Keinen zur Suchmaske " & Chr(34) & Suchmaske & "*.*" & Chr(34) & _  
        " passenden Ordner gefunden!", vbCritical, "Ordner nicht gefunden!"  
End If

End Sub

Sub SearchInFolder(Ordner)
' Alle Unterordner überprüfen  
For Each UO In Ordner.SubFolders
    'Beginnt Ordnername mit Suchmaske?  
    If LCase(Left(UO.Name, SuchLen)) = Suchmaske Then
        'Änderungsdatum vergleichen ...  
        If UO.DateLastModified > Zuletzt Then
            '... und wenn neuer, speichern;  
            Zuletzt = UO.DateLastModified
            'Ordnerpfad natürlich auch  
            Erg = UO.Path
        End If
    End If
Next

'Unterordner abklappern, SearchInFolder rekursiv aufrufen  
For Each Unter In Ordner.SubFolders
    SearchInFolder Unter
Next
End Sub
In dieser Fassung wird der gesamte Ordnerpfad in die Zelle A1 der "Tabelle1" geschrieben - soll's wirklich nur der Name sein, dann "Erg = UO.Path" auf "Erg = UO.Name" ändern.

Um das Suchergebnis in die Zwischenablage zu bekommen (geht's denn wirklich nicht anders?) käme die von Dir beschriebene Vorgangsweise oder eine der unter den folgenden Links zu findenden Methoden in Frage:

http://209.85.135.104/search?q=cache:z7BWmbS8JbAJ:mypage.bluewin.ch/rep ...
http://www.aboutvb.de/vba/artikel/vbaclipboard.htm

Grüße
bastla

P.S.: Die "Datei-Such-Variante" hat bei einem Test mit ca 160.000 Dateien bei mir auch knapp 4 Minuten gebraucht (allerdings auf einer lokalen internen SATA-Platte).

[Edit] Den Plan C (Ordnerliste in Batch) können wir ja immer noch versuchen ... [/Edit]
Mitglied: bastla
bastla 27.11.2007 um 17:50:00 Uhr
Goto Top
Hallo MichaelS87!

Soferne die Nummerierung tatsächlich ausreichend ist, um den jüngsten Ordner / die jüngste Datei zu finden (und es nur eine Ordnerebene unterhalb von "W:\m1", etc gibt), müsste es so gehen:
@echo off & setlocal
set "Start=W:\m1 W:\m2 W:\m3 W:\m4 X:\m1"  
set "Neueste=C:\Neueste.txt"  

set "List=%temp%\whatever.xyz"  
set /p "Maske=Bitte Suchmaske eingeben: "  
echo.
echo.
if exist "%List%" del "%List%"  
if exist "%Neueste%" del "%Neueste%"  
for %%S in (%Start%) do for /f "delims=" %%A in ('dir /b /ad "%%S\%Maske%*.*" 2^>nul') do echo %%~nA$%%~fA >>"%List%"  
set Neu=
if exist "%List%" (  
	for /f "tokens=2 delims=$" %%N in ('sort "%List%"') do set "Neu=%%N"  
	del "%List%"  
)
if defined Neu (
	echo %Neu%
	echo %Neu% >"%Neueste%"  
	) else (
	echo [%Maske%] nicht gefunden!
	echo.
	pause
)
Hoffentlich empfindest Du es nicht als Zwangsbeglückung, wenn Du als Ergebnis nicht die gesamte Liste, sondern nur einen Eintrag (im CMD-Fenster sowie in "C:\Neueste.txt") erhältst face-wink.

Ganz wohl fühle ich mich allerdings mit der Strategie "nach Ordnernamen sortieren" nicht:
Wenn Du keine einheitliche Namenskonvention verwendest, geht das nämlich mit 2- oder mehrstelligen Nummern schief, da eine Textsortierung verwendet wird und daher zB gilt: "aaa_12.txt" < "aaa_2.txt". Die angesprochene Konvention müsste lauten: "Die Nummern aller Ordner-/Dateinamen weisen die gleiche Stellenanzahl auf." Im oben genannten Beispiel würde dies bedeuten, dass als Name "aaa_02" (oder als Vorsorge für dreistellige Nummern "aaa_002") zu verwenden wäre.

Grüße
bastla

[Edit] Delimiter "§" durch "$" ersetzt, da "§" > "_" und "$" < "_", was bei Verwendung von "§" und fehlendem "_" im Ordnernamen zu falscher Sortierung führte) [/Edit]
Mitglied: Biber
Biber 27.11.2007 um 18:11:44 Uhr
Goto Top
Moin bastla.

eine Code-Verschlankung schlage ich noch vor.

Statt der beiden hintereinandergeschalteten FOR-Anweisungen einfacher:

...
@echo off & setlocal EnableDelayedExpansion
set "Start=W:\m1\# W:\m2\# W:\m3\# W:\m4\# X:\m1\#"  
....
for /f "delims=" %%A in ('dir /b /ad "!Start:#=%Maske%*.*" 2^>nul') do echo %%~nA§%%~fA >>"%List%"  
...
...
denn der DIR-Befehl lann ja durchaus mehrere Datei/Pfadangaben in einer Zeile verwerten.

Grüße
Biber
Mitglied: bastla
bastla 27.11.2007 um 18:21:18 Uhr
Goto Top
Hallo MichaelS87!

Damit hast Du einen weiteren Hinweis auf die Notwendigkeit der oben erwähnten Konvention. Wenn der Ordner "aaa_0" hieße, würde es klappen.

Grüße
bastla
Mitglied: bastla
bastla 27.11.2007 um 18:36:05 Uhr
Goto Top
Hallo MichaelS87!

Einfachere Lösung: Ersetze die beiden im Batch vorkommenden "§" durch "$" (ich mache das auch gleich oben im Code).

Grüße
bastla