Powershell Fehler beim Kopieren / Verschieben / Umbenennen, wenn der Dateiname [eckige Klammern] enthält?

9

Bitte entschuldigen Sie eine Noob-Frage, aber diese Frage hat mich völlig verblüfft.

Ich habe ein "Einzahler" -Verzeichnis, in dem vom Benutzer eingereichte Dateien eintreffen, und habe keine Kontrolle über die eingehenden Dateinamen.

Ich habe in PS einen Parser erstellt, der Dateien (basierend auf dem Inhalt des Dateinamens) recht erfolgreich an ein geeignetes Ziel verschiebt.

Dies funktioniert einwandfrei, AUSSER wenn ein Dateiname entweder "[" oder "]" enthält.

Hier ist der Vorprozessor "Umbenennen", der eine Datei mit einem der lästigen Klammerzeichen nicht umbenennt:

 cd $folderpath
 foreach ($i in get-childitem $folderpath) {   
     if ($i.mode.substring(0,1) -ne “d”) {
        $name = $i.name.replace("[","_")
        $name = $name.replace("]","_")
        Write-Host $i -foregroundcolor “blue”       
        Write-Host $name -foregroundcolor “green”  

        Rename-Item $i $name 

     }
 }

Dies schlägt auch für ren, copy, move und ihre Cmdlet-Entsprechungen fehl

Jeder Einblick, den Sie möglicherweise gewähren können, wäre sehr willkommen.

Danke im Voraus . . .

TTrewitt
quelle
Arbeit an dir Flucht-Fu: techotopia.com/index.php/…
RobotHumans
1
@ aking1012: Das funktioniert für Literale, aber nicht für Variablen.
Bis auf weiteres angehalten.

Antworten:

8

Wenn Sie nicht verwenden -LiteralPath, verursachen eckige Klammern echte Probleme beim Entkommen von Zeichen. Das Problem ist darauf zurückzuführen, dass PowerShell die Zeichenfolgen mehrmals intern entfernt und Sonderzeichen für den Mustervergleich verwendet. Es ist komplex, PowerShell dazu zu bringen, eine wörtliche eckige Klammer in einer Pfadzeichenfolge korrekt zu erkennen.

Wenn Sie Zeichenfolgen in einfachen Anführungszeichen verwenden, benötigt eine Klammer zwei Backticks, um sie zu umgehen. Wenn Sie Zeichenfolgen in doppelten Anführungszeichen verwenden, benötigt eine Klammer vier Backticks, um sie zu umgehen.

Wenn Sie nach einer Datei mit dem Namen suchen MyFile[1].txt, müssen Sie Folgendes verwenden:

'MyFile``[1``].txt'

oder:

"MyFile````[1````].txt"

Ja, es ist ein Schmerz. Um zu sehen, warum dies so ist, müssen Sie wissen, was los ist. Es ist einfach, dies rückwärts zu tun.

Angenommen, Sie möchten eine Datei mit dem wörtlichen Namen erhalten [ab].txt.

Der Wildcard-Mustervergleich Get-ChildItembedeutet, dass, wenn er [ab].txtals Pfad abgerufen wird, nach Dateien mit dem Namen a.txt und gesucht wird b.txt. Wenn wir also einem Literal entsprechen möchten [ab].txt, müssen wir unsere Klammern mit dem Escape-Zeichen: dem Backtick, maskieren. Das gibt uns dies als die tatsächliche Zeichenfolge an, die wir Get-ChildItemfür die Dateispezifikation verwenden möchten:

`[ab`].txt

Wir müssen diese Dateispezifikation jedoch als Zeichenfolge übergeben. Das heißt Get-ChildItem, wir werden diesen Backticks entkommen, aber das wollen wir nicht! Wir wollen buchstäbliche Backticks. Wir umgehen die Backticks mit Backticks in unserer Zeichenfolge, um sicherzustellen, dass Get-ChildItemdie richtige Dateispezifikation verwendet wird:

'``[ab``].txt'

Wenn wir Zeichenfolgen in doppelten Anführungszeichen verwenden möchten, müssen wir jeden Backtick erneut maskieren , da die Zeichenfolge in doppelten Anführungszeichen die Zeichenfolge nicht mehr enthält. Und so kommt man dazu:

"````[ab````].txt"

Aus diesem Grund haben so viele PowerShell-Funktionen, die Dateispezifikationen verwenden, die -LiteralPathOption.

Speckwürfel
quelle
5

RenameItemhat -LiteralPathaus irgendeinem dummen Grund keine . * *

Move-Item -LiteralPath $i -destination $name

* Ausreden von einem Co-Designer der Sprache.

Bis auf weiteres angehalten.
quelle
Move-Item -LiteralPath $ i -destination $ name löst diesen Fehler aus: Rename-Item: Es wurde kein Parameter gefunden, der dem Parameternamen 'LiteralPath' entspricht.
TTrewitt
@TTrewitt: Welche Version von PS?
Bis auf weiteres angehalten.
Der Link in dieser Antwort ist 404 gegangen. Kennt jemand einen Ersatz?
Philip Kendall
@PhilipKendall: Ich habe den Link repariert.
Bis auf weiteres angehalten.
2

Damit wurde schließlich das gewünschte Ergebnis erzielt:

foreach ($i in get-childitem $folderpath) {
  if ($i.mode.substring(0,1) -ne “d”) {
    $name = $i.name.replace("[","_")
    $name = $name.replace("]","_")

   Write-Host $name -foregroundcolor “green”    
   [System.IO.File]::Move($folderPath+"\"+$i, $folderPath+"\"+$name) 
  }
}
TTrewitt
quelle