Dateien mit großgeschriebener Extension finden u. umbenennen

German support forum

Moderators: Hacker, Stefan2, white

User avatar
Dalai
Power Member
Power Member
Posts: 9990
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Dateien mit großgeschriebener Extension finden u. umbenennen

Post by *Dalai »

Hallo liebe Leser & Helfer :)

ich bin ein ordnungsliebender Mensch, jedenfalls was Dateien auf meinem Rechner betrifft :wink:. Deswegen mag ich auch keine großgeschriebenen Extensions, egal welchen Dateityps.

Nun habe ich häufiger den Fall, dass doch mal eine Extension großgeschrieben ist und das möchte ich - möglichst automatisiert - ändern. Bislang arbeite ich mit einer Suche im TC, die sich aber erstens auf den Dateityp JPG beschränkt (Suche mit Plugins, tc | Erweiterung | =(groß/klein) | JPG) und zweitens weitere Interaktion erfordert: Suchergebnis ins Panel legen, Dateien markieren, MUT aufrufen und umbenennen.

Ziel ist es, z.B. einen Button zu drücken und irgendein Prozess legt mit der Suche los und benennt die Dateien selbsttätig um.

Ich dachte erst an ein AutoIt-Skript, aber leider fehlt dieser Sprache eine Funktion, die Dateien umbenennen kann. Es gibt nur FileMove(), aber diese Funktion führt natürlich dazu, dass eine Datei auf sich selbst verschoben würde. Alternativ könnte man jede Datei in ein temporäres Verzeichnis schieben und dann wieder zurück, aber das ist dann eher von hinten durch die Brust ins Auge ;).

Wie würdet ihr in einem solchen Fall vorgehen? Ich kann mich erinnern, dass es irgendein Skripting-Plugin für den TC gibt, aber konkreter ist meine Erinnerung leider nicht...

MfG Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
User avatar
Peter
Power Member
Power Member
Posts: 2068
Joined: 2003-11-13, 13:40 UTC
Location: Schweiz

Post by *Peter »

Mit dem Plugin kann ich dir dienen:
http://www.totalcmd.net/plugring/script_wdx.html

mit dessen Funktion leider nicht ...

Peter
TC 10.xx / #266191
Win 10 x64
User avatar
Dalai
Power Member
Power Member
Posts: 9990
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Post by *Dalai »

Peter wrote:Mit dem Plugin kann ich dir dienen:
http://www.totalcmd.net/plugring/script_wdx.html
Schön, dass mich meine Erinnerung nicht trog. Dumm nur, dass ich von VBS und JS null Peilung habe :(.

MfG Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
User avatar
Peter
Power Member
Power Member
Posts: 2068
Joined: 2003-11-13, 13:40 UTC
Location: Schweiz

Post by *Peter »

Dalai wrote:Schön, dass mich meine Erinnerung nicht trog. ....
:D
Dalai wrote:...null Peilung habe...
:shock:

Welch berauschend breite Bandbreite der Ausdrucksformen :lol: :lol:

Ich denke: wie gewohnt - hier werden sie geholfen. Es gibt hier ein paar Scriptspezialisten, die sich auch deiner annehmen werden.

Peter
TC 10.xx / #266191
Win 10 x64
User avatar
GammelBert
Member
Member
Posts: 109
Joined: 2007-02-21, 18:42 UTC
Location: Germany

Post by *GammelBert »

Wenn du keine andere Sprache beherrschst, dann nimm halt AutoIt.
JOUBE
Power Member
Power Member
Posts: 1675
Joined: 2004-07-08, 08:58 UTC

Post by *JOUBE »

Ein Umbenennen auf den selben Namen, wobei sich nur die Gross-/Kleinschreibung ändern soll, ist meines Erachtens nach sowieso nicht möglich unter Windows und mit NTFS (vielleicht auch bei FAT/Fat32 ?). Das liegt vielleicht daran, dass Windows ja - im Prinzip - nicht zwischen Gross- und Kleinschreibung unterscheidet.

Deshalb ist ein Filemove() wahrscheinlich schon das richtige Werkzeug für die Aufgabe:

Test.TXT -> Test.txt$ -> Test.txt

Nach meinem Verständnis ist ein Filemove() sowieso das gleiche wie ein Rename(), zumindestens solange man sich innerhalb eines Laufwerks/einer Partition bewegt ( Rename() ist Teilmenge von Filemove() ).

JOUBE
User avatar
Dalai
Power Member
Power Member
Posts: 9990
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Post by *Dalai »

GammelBert wrote:Wenn du keine andere Sprache beherrschst, dann nimm halt AutoIt.
Das hab ich nicht gesagt. Es gibt ja noch mehr Sprachen wie Delphi, Batch (auch wenn das keine "Sprache" ist), AutoHotkey usw. Nur fragte ich ja nach Ideen und wie andere Leute das Problem angehen würden. Mir wäre sowieso eine TC-interne Lösung lieber, sofern sie nicht zuviel Aufwand bzgl. Plugins und Benutzung bedeutet.
JOUBE wrote:Ein Umbenennen auf den selben Namen, wobei sich nur die Gross-/Kleinschreibung ändern soll, ist meines Erachtens nach sowieso nicht möglich unter Windows und mit NTFS (vielleicht auch bei FAT/Fat32 ?).
Der TC beweist das Gegenteil, wenn man dort im MUT die Funktionalität zur Änderung der Schreibung benutzt ;). Der wird doch keine temporären Dateien erzeugen (dafür geht das Umbenennen zu schnell).
Das liegt vielleicht daran, dass Windows ja - im Prinzip - nicht zwischen Gross- und Kleinschreibung unterscheidet.
Es ist mir klar, dass Windows keine Unterscheidung macht sondern nur das darunterliegende NTFS. Aber selbst FAT32 kann die Groß- und Kleinschreibung speichern.
Deshalb ist ein Filemove() wahrscheinlich schon das richtige Werkzeug für die Aufgabe:

Test.TXT -> Test.txt$ -> Test.txt
Mmh, an eine temporäre Datei im selben Verzeichnis habe ich zugegebenermaßen noch nicht gedacht. Werde ich mal ausprobieren.
Nach meinem Verständnis ist ein Filemove() sowieso das gleiche wie ein Rename(), zumindestens solange man sich innerhalb eines Laufwerks/einer Partition bewegt
In einem solchen Fall eben nicht mehr.

MfG Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
JOUBE
Power Member
Power Member
Posts: 1675
Joined: 2004-07-08, 08:58 UTC

Post by *JOUBE »

Dalai wrote:temporären Dateien
Ein FileMove()/Rename() erzeugt keine temporäre Datei. Das ist ein völliges Missverstehen des Vorgangs. Auf einer Partition sowieso nicht, beim Verschieben auf eine andere Platte wird kopiert und anschliessend gelöscht (-> auch keine temporäre Datei). Da beim Move() und Rename() innerhalb einer Partition niemals Inhalte verschoben/kopiert werden, sondern nur Verzeichiseinträge geändert (ggf umgehängt [1]) werden, ist dieser Vorgang immer ungleich schneller als ein Kopieren von Inhalten.

JOUBE

[1] Beim Verschieben in ein anderes Verzeichnis wird nur der Verzeichniseintrag umgehängt, sozusagen ein Umbenennen des Pfads durchgeführt.
User avatar
Hacker
Moderator
Moderator
Posts: 13142
Joined: 2003-02-06, 14:56 UTC
Location: Bratislava, Slovakia

Post by *Hacker »

Dalai,

Code: Select all

Loop, *.*, 0, 1
{
	StringUpper, UpperCaseExt, A_LoopFileExt
	IfEqual, A_LoopFileExt, %UpperCaseExt%
	{
		RegExMatch(A_LoopFileName, "(.*)\.", FullNameWithoutExt)
		StringLower, LowerCaseExt, A_LoopFileExt
		FileMove, %A_LoopFileFullPath%, %FullNameWithoutExt1%.%LowerCaseExt%, 1
	}
}
Klappert alle Verzeichnisse unter dem aktuellen (inklusive) rekursiv ab und ändert jede grossgeschriebene Erweiterung in eine kleingeschriebene um. Es werden nur Erweiterungen wie XYZ in Betracht gezogen, nicht Xyz, XyZ, xYz oder ähnliche.

HTH
Roman
Mal angenommen, du drückst Strg+F, wählst die FTP-Verbindung (mit gespeichertem Passwort), klickst aber nicht auf Verbinden, sondern fällst tot um.
User avatar
Dalai
Power Member
Power Member
Posts: 9990
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Post by *Dalai »

JOUBE wrote:
Dalai wrote:temporären Dateien
Ein FileMove() erzeigt keine temporäre Datei. Das ist ein völliges Missverstehen des Vorgangs.
Nö, ich verstehe das nicht miss. Ich schrieb ja genau das: TC erzeugt keine temp. Dateien, egal, ob ein neuer Name für eine Datei vorliegt oder derselbe Name in anderer Schreibweise.
Dalai wrote:MfG Dalai
Locker bleiben...
Ich bin locker.

MfG Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
JOUBE
Power Member
Power Member
Posts: 1675
Joined: 2004-07-08, 08:58 UTC

Post by *JOUBE »

Hacker wrote:Es werden nur Erweiterungen wie XYZ in Betracht gezogen, nicht Xyz, XyZ, xYz oder ähnliche.
Das könnte man erledigen, indem man im Script die "gelowerte" Extension mit der originalen Extension vergleicht und bei Ungleichheit in Aktion tritt.

JOUBE
User avatar
Hacker
Moderator
Moderator
Posts: 13142
Joined: 2003-02-06, 14:56 UTC
Location: Bratislava, Slovakia

Post by *Hacker »

JOUBE wrote:Das könnte man erledigen, indem man im Script die "gelowerte" Extension mit der originalen Extension vergleicht und bei Ungleichheit in Aktion tritt.
Soweit das erwünscht ist, sicherlich.

Roman
Mal angenommen, du drückst Strg+F, wählst die FTP-Verbindung (mit gespeichertem Passwort), klickst aber nicht auf Verbinden, sondern fällst tot um.
JOUBE
Power Member
Power Member
Posts: 1675
Joined: 2004-07-08, 08:58 UTC

Post by *JOUBE »

Dalai wrote:
Dalai wrote:MfG Dalai
Locker bleiben...
Ich bin locker.
Vielleicht. Aber hastig. ;-) Denn den zitierten Teil gibt es gar nicht (mehr), und zwar so früh schon nicht mehr, dass mein Posting sogar noch nicht einmal mit "geändert" markiert worden ist...

So, das Problem ist ja vermutlich gelöst.

JOUBE
User avatar
HolgerK
Power Member
Power Member
Posts: 5411
Joined: 2006-01-26, 22:15 UTC
Location: Europe, Aachen

Post by *HolgerK »

Die geschwätzige VBS-Variante:

Code: Select all

If WScript.arguments.Count > 1 Then
  sStartpath = WScript.arguments.Item( 0 )
  sExtension = WScript.arguments.Item( 1 )  
  Set oFSO = CreateObject( "Scripting.FileSystemObject" )
  RecursiveRenameExtension(sStartPath)
Else
  WScript.Echo "Parameter missing!"& VbCrLf & VbCrLf &_
  "Command   : RecursiveChangeExtension.vbs"& VbCrLf &_
  "Parameters: ""%P"" jpg"& VbCrLf &_
  "Tooltip   : rekursive change extension (to lower/upper or camelCase"& VbCrLf &_
  "First parameter is start path (e.g. %P)"& VbCrLf &_
  "Second parameter is extension (e.g. Cmd)"& VbCrLf &_
  "Second parameter can be < or > to change all extension to lower or upper"
End If

Function RecursiveRenameExtension(sPath)

  set oFolder =  oFSO.GetFolder(sPath)

  set oFiles = oFolder.Files
  For Each oFile in oFiles
    sExt = oFSO.GetExtensionName( oFile.Name )
    sName =  oFSO.GetBaseName(oFile.Name)
      If sExtension = "<" Then
        sNewFileName = sName & "." & LCase(sExt)
      Elseif sExtension = ">" Then
        sNewFileName = sName & "." & UCase(sExt)
      Elseif LCase(sExtension) = LCase(sExt) And Not sExtension = sExt Then
        sNewFileName = sName & "." & sExtension
      Else
        sNewFileName = ""
      End If
      If Not sNewFileName = "" And Not sNewFileName = oFile.Name Then
        oFile.Name =  sNewFileName & "@$"
        oFile.Name =  sNewFileName
      End If
  Next

  set oSubFolders = oFolder.SubFolders
  For Each oFolder in oSubFolders
    RecursiveRenameExtension(oFolder.Path)
  Next   

End Function 
Gruß
Holger

Edith hat einen Bug gefunden: oFolder.Path anstelle von oFolder.Name
User avatar
Dalai
Power Member
Power Member
Posts: 9990
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Post by *Dalai »

Ich weiß nun einmal mehr, warum ich kein AutoHotkey verwende: is das unübersichtliche Syntax... :shock:. Die Loop ist komfortabel, keine Frage, weil man keine Funktion für die rekursive Suche schreiben muss, aber irgendwie erinnert mich das an AutoIt2 (wovon es ja abstammt) und den Krampf damit damals...

Da ich große Verzeichnisstrukturen habe, deren Verarbeitung in einem solchen Fall entsprechend lange dauert, braucht es natürlich eine Ausgabe über den Fortschritt. Und da ich AutoHotkey und VBS aus genannten Gründen nicht verwende, habe ich ein etwas umfangreicheres aber dafür komfortableres AutoIt-Skript zusammengebaut. Außerdem wollte ich sowieso eine Funktion zum rekursiven Finden von Dateien bauen, weil ich die vor kurzem schonmal benötigte und dann stattdessen die einfache Methode mit "dir /b /s" wählte :).

Die Ausgabe des Skriptes kann dann z.B. so aussehen. Die erst in den letzten Minuten eingebaute Prozentanzeige ist auf dem Bild nicht zu sehen, weil es an der Stelle nicht genügend Daten zu verarbeiten hatte ;).

OK, kommen wir zum Quellcode:
RecursiveExtensionRename.au3:

Code: Select all

;
; AutoIt Version: 3.3.4.0+
; Language:       English
; Platform:       Win2000/XP/2003/Vista/7
; Author:         Dalai
;
; Last Update: 03.08.2011
;
; Script Function:
;    Do recursive file search and rename extensions of files with upper-case
;    extension to lower-case
;
; ----------------------------------------------------------------------------
; Set up our defaults
; ----------------------------------------------------------------------------

#include <Timers.au3>
#include "library_3340.inc"

;AutoIt einstellen:
;Shows the current script line in the tray icon tip to help debugging
AutoItSetOption("TrayIconDebug", 1)
AutoItSetOption("MustDeclareVars", 1)


; ----------------------------------------------------------------------------
; Script Start
; ----------------------------------------------------------------------------

global const $OUTINTERVAL = 500

global $arFiles
global $i, $count, $percent = 0, $time
global $sDrive, $sDir, $sName, $sExt, $_ext, $new
;-- input vars
global $Path, $Ext

if $CmdLine[0] < 2 then
    MsgBox(64, "Usage", "Command: " & @ScriptName & @CRLF & _
                       'Parameter: "%P" jpg' & @CRLF & _
                       "First parameter: path to process including all subdirs (recursive)" & @CRLF & _
                       "Second parameter: extension to rename (use * for all files)")
    Exit
EndIf

;--- Get input values
$Path = $CmdLine[1]
if (StringRight($Path, 1) == "\") then $Path = StringTrimRight($Path, 1)
$Ext = $CmdLine[2]

;--- Do some output
_ConsoleWriteLine(StringFormat("Searching for *.%s in", $Ext))
;--- Build array of files matching the pattern
$arFiles = _RecursiveFileListToArray($Path, "*." & $Ext, 1)

if IsArray($arFiles) then
    _ConsoleWriteLine(StringFormat(@CRLF & "Found %d files matching *.%s", _Pred($arFiles[0]), $Ext))
    _ConsoleWriteLine("Looking for files with upper-case extension ...")
    ;--- Init timer
    $time = _Timer_Init()
    ;--- Loop through the generated array
    for $i=1 to _Pred($arFiles[0])
        ;--- If time since last output was longer ago
        ;    than specified interval
        if (_Timer_Diff($time) >= $OUTINTERVAL) then
            ;--- calculate percentage
            $percent = ($i * 100 / _Pred($arFiles[0]))
            _ConsoleWriteLine(StringFormat("%d %", $percent))
            ;--- save new timer value
            $time = _Timer_Init()
        EndIf
        ;_ConsoleWriteLine($arFiles[$i])
        ;--- Split the full path into its contents
        _PathSplit($arFiles[$i], $sDrive, $sDir, $sName, $sExt)
        ;--- Remove the leading period from the extension
        $sExt = StringTrimLeft($sExt, 1)
        ;--- Handle the case meaning all files properly
        if ($Ext == "*") then
            $_ext = StringLower($sExt)
        Else
            $_ext = $Ext
        EndIf
        if (StringUpper($_ext) == $sExt) then
            ConsoleWrite(StringFormat("    Rename %s ...", StringFormat("%s.%s", $sName, $sExt)))
            ;--- Generate new path with lower-case extension
            $new = _PathMake($sDrive, $sDir, $sName, StringLower($sExt))
            ;--- Because FileMove() isn't able to rename a file to the same name with different case
            ;    it must be renamed to a different name und then "moved" back to the target name
            if (FileMove($arFiles[$i], $new & "$") AND (FileMove($new & "$", $new))) then
                $count += 1
                _ConsoleWriteLine("  OK")
            Else
                _ConsoleWriteLine("  Error!")
            EndIf
        EndIf
    Next
    ;--- Output summary
    _ConsoleWriteLine(StringFormat(@CRLF & "Finished. Renamed %d files", $count))
Else
    _ConsoleWriteLine("Path not found or something went wrong!")
EndIf
library_3340.inc:

Code: Select all

#include <Array.au3>
#include <File.au3>

; #FUNCTION# ====================================================================================================================
; Name...........: _RecursiveFileListToArray
; Description ...: Finds files with specified pattern recursively
; Syntax.........: _RecursiveFileListToArray($sPath[, $sMask = "*"[, $iStdOut = 0]])
; Parameters ....: $sPath   - Path to generate filelist for.
;                  $sMask   - Optional the filter to use, default is *. Search the Autoit3 helpfile for the word "WildCards" For details.
;                  $iStdOut - Optional:
;                  |$iStdOut=0(Default) don't output anything
;                  |$iStdOut=1 output processed dirs only
;                  |$iStdOut=2 output found files only
;                  |$iStdOut=3 output processed dirs and found files
; Return values .: Success: an Array holding the file names
;                  Failure: 0 (files not found)
;                  @Error:  1 - $sPath invalid or not found or not accessible
; Author ........: Dalai
; Modified.......:
; Remarks .......: The array returned is one-dimensional and is made up as follows:
;                                $array[0] = Number of Files returned
;                                $array[1] = 1st File
;                                $array[2] = 2nd File
;                                $array[3] = 3rd File
;                                $array[n] = nth File
; Related .......: _FileListToArray
; Link ..........:
; Example .......: Not yet
; Note ..........:
;------------------------------------------------------------------------------
Func _RecursiveFileListToArray($sPath, $sMask = "*", $iStdOut = 0, $iDepth = 0)
    local $tempArray, $dirArray, $resArray
    local $full

    ;--- Exit if $sPath doesn't exist
    if not FileExists($sPath) then Return SetError(1, 0, 0)
    if (StringRight($sPath, 1) == "\") then $sPath = StringTrimRight($sPath, 1)

    $iDepth += 1

    ;--- Write to console
    if (Mod($iStdOut, 2) > 0) then
        _ConsoleWriteLine($sPath)
    EndIf

    $tempArray = _FileListToArray($sPath, $sMask, 1)
    if IsArray($tempArray) then
        for $i=1 to $tempArray[0]
            $tempArray[$i] = $sPath & "\" & $tempArray[$i]
            if $iStdOut >= 2 then _ConsoleWriteLine($tempArray[$i])
        Next
;         _ArrayDisplay($tempArray, "temp")
        if IsArray($resArray) then
            _ArrayConcatenate($resArray, $tempArray, 1)
        Else
            $resArray = $tempArray
        EndIf
    EndIf

    $dirArray = _FileListToArray($sPath, "*", 2)
    if IsArray($dirArray) then
;         _ArrayDisplay($dirArray, "dir")
        for $i=1 to $dirArray[0]
            $full = $sPath & "\" & $dirArray[$i]
            $tempArray = _RecursiveFileListToArray($full, $sMask, $iStdOut, $iDepth)
            if IsArray($tempArray) then
                if IsArray($resArray) then
                    _ArrayConcatenate($resArray, $tempArray, 1)
                Else
                    $resArray = $tempArray
                EndIf
            EndIf
        Next
    EndIf

    if IsArray($resArray) then
        $resArray[0] = UBound($resArray)
        Return $resArray
    EndIf
    Return 0
EndFunc    ;==>_RecursiveFileListToArray

;-----------------------------------------------------------

Func _ConsoleWriteLine(const $msg)
    ConsoleWrite($msg & @CRLF)
EndFunc
Um die Ausgabe zu sehen, muss das Skript natürlich mit Aut2Exe als Konsolenanwendung kompiliert werden. Das nur als Hinweis an diejenigen, die das Skript verwenden möchten.

Das kompilierte Skript dann auf einen Button gelegt und los geht's:

Code: Select all

TOTALCMD#BAR#DATA
cmd /k
""E:\Eigene Dateien\Skripte\RecursiveExtensionRename.exe" "%P" jpg"
wcmicons.dll,22
Rekursives Kleinschreiben der Extension aller Bilder


-1
MfG Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
Post Reply