Dateinamen für den Fall auf der Festplatte speichern?

7

Ich habe eine Datei README.TXT. Wenn ich den folgenden Befehl gebe:

PS> Get-Item ReadMe.txt

... dann wird "ReadMe.txt" zurückgegeben. Ich möchte den tatsächlichen Namen der Datei auf der Festplatte herausfinden, einschließlich Groß- und Kleinschreibung. Wie kann ich "README.TXT" zurückgeben?

Ich frage, weil ich versuche, ein Problem mit Dateinamen ohne Berücksichtigung der Groß- und Kleinschreibung unter Windows im Vergleich zu Dateien mit Groß- und Kleinschreibung auf einer Unix-Box aufzuspüren, und ich möchte, dass die tatsächliche Groß- und Kleinschreibung auf der Windows-Box verwendet wird.

Weitere Details: Ich habe eine Liste von Dateien (in einer .CSPROJDatei gespeichert ), die sich in einem anderen Fall als die auf der Festplatte gespeicherten befinden. Ich möchte sicher sein, dass sie übereinstimmen. Beispiel: Wenn in der .CSPROJDatei "ReadMe.txt" angegeben ist, die Datei auf der Festplatte jedoch "README.TXT" lautet, wird die Datei beim Bearbeiten der Datei in Visual Studio manchmal als "ReadMe.txt" neu geschrieben, wodurch Perforce verwirrt wird, da dies der Fall ist -sensitiv, und der Dateiname hat nicht mehr den erwarteten Fall. Ich möchte ein Skript schreiben, das die nicht übereinstimmenden Dateinamen erkennt, damit ich etwas dagegen tun kann, bevor es ein Problem verursacht.

Roger Lipscombe
quelle

Antworten:

3

Folgendes habe ich mir ausgedacht:

function Get-ActualFileName($file) {
    $parent = Split-Path $file
    $leaf = Split-Path -Leaf $file

    $result = Get-ChildItem $parent | where { $_ -like $leaf }
    $result.Name
}
Roger Lipscombe
quelle
Danke dafür. Aber ich brauche das für den FullName. Was kann ich ändern?
Masterxilo
2

Die folgende PowerShell-Funktion basiert auf der eleganten Lösung eines anderen Entwicklers für C # unter https://stackoverflow.com/a/11436327/854680 .

Da Get-ChildItem nicht verwendet wird, ist es viel schneller , was einen Unterschied macht, wenn diese Funktion Dutzende oder Hunderte Male aufgerufen wird .

function Get-FileNameTrueCase {
    Param (
        [parameter(Mandatory=$true)]
        [string]
        $DirOrFile
    )

    if (-not ( (Test-Path $DirOrFile -PathType Leaf) -or (Test-Path $DirOrFile -PathType Container) ) ) {
        # File or directory not found
        return $DirOrFile
    }

    $TruePath = "";
    foreach ($PathPart in $DirOrFile.Split("\")) {
        if ($TruePath -eq "") {
            $TruePath = $PathPart.ToUpper() + "\";
            continue;
        }
        $TruePath = [System.IO.Directory]::GetFileSystemEntries($TruePath, $PathPart)[0];
    }
    return $TruePath;
}
MikeOnline
quelle
Vielen Dank für die Verknüpfung
Ivan Ferrer Villa
Vielen Dank für diese Variante, die einen vollständigen Pfad ausgibt. Grundsätzlich entspricht dies dem Klicken mit der rechten Maustaste auf eine Datei im Explorer und der Auswahl von "Als Pfad kopieren".
Masterxilo
1

Der Großteil der Dateisystemarbeit in PowerShell wird von einigen .NET-Klassen im System.IO-Namespace ausgeführt. Wenn Sie den Pfad kennen (wie in Ihrem Beispiel, Sie haben zum Speicherort des Dateisystems navigiert, in dem sich Ihre Betreffdatei befindet), können Sie Folgendes verwenden

(get-item $pwd).GetFiles('readme.txt')

Da bei den .NET-Basisklassen zwischen Groß- und Kleinschreibung unterschieden wird, wird bei der Ausgabe Ihrer Dateinamen auch zwischen Groß- und Kleinschreibung unterschieden.

Als Referenz rufen Sie im Beispiel die GetFiles-Methode des System.IO.DirectoryInfo-Objekts auf, das das aktuelle Arbeitsverzeichnis darstellt ($ pwd). Sie können dies ändern, um auf das Verzeichnis zu verweisen, das die Datei enthält, für die Sie das Gehäuse bestätigen müssen.

Die Eigenschaften Name, BaseName und FullName sollten alle das richtige Gehäuse widerspiegeln.

Weitere Informationen zur GetFiles-Methode.

Steven Murawski
quelle
1
Nein, diese geben den Pfad zurück, wie auch immer Sie ihn eingegeben haben. Beispiel: cd C: \ WINDOWS \ SYSTEM32; (get-item $ pwd) .GetFiles (". \ w32time.dll"). FullName # Gibt "C: \ WINDOWS \ SYSTEM32 \. \ w32time.dll" aus, das nicht nur falsch geschrieben ist, sondern auch ein \. \ darin, weil ich es so geschrieben habe ...
Jaykul
1

Verwenden Sie einfach einen Platzhalter, anstatt den genauen Namen anzugeben:

PS> Get-Item ReadMe.tx?

dies sollte zurückkehren README.TXT

Peter Hahndorf
quelle
Besser hoffen, dass eine Datei Readme.tx0 nicht existiert
scobi
0

Der schnellste Weg, den ich mir vorstellen kann, besteht darin, alle Schrägstriche durch * \ zu ersetzen und dann Get-Item aufzurufen. Um sicherzustellen, dass Sie keine Dupes erhalten, wählen Sie den aus, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird.

$Path = Get-Item "$($Path.TrimEnd('\/') -replace "(?<!:)(\\|/)", '*$1')*" |
           Where { $_.FullName -ieq $Path } | Convert-Path
Jaykul
quelle
0

Hier ist mein schneller und schmutziger Ansatz (keine Validierung):

Function Resolve-PathName { [CmdletBinding()]
Param(
    [Parameter(ValueFromPipelinebyPropertyName,ValueFromPipeline,Mandatory)]
    [Alias("Fullname")]
    [string] $File,
    [switch] $Cygpath
) Process {
    $cur = $File
    $stack = New-Object System.Collections.Stack

    while ( $cur.length -gt 0) {
        $stack.Push( (split-path $cur -Leaf) )
        $cur = split-path $cur
    }
    $cur = get-item ($stack.pop())
    while ( $stack.Count -gt 0) {
        $cur = $cur | Get-ChildItem -Filter ($stack.Pop())
    }
    if ($Cygpath) {
        cygpath $cur.Fullname
    } else {
        $cur.Fullname
    }
}}
Hassan
quelle
Warum sollte es CygWin auf einer Produktionsmaschine geben?
Deer Hunter