【问题标题】:How do I remove periods from file names using PowerShell?如何使用 PowerShell 从文件名中删除句点?
【发布时间】:2019-12-13 22:59:33
【问题描述】:

我正在尝试在 PowerShell 中编写一个脚本,该脚本在文件夹中搜索包含不必要句点的文件,然后从文件名中大量删除句点。

例如。 Example.File.doc ---> ExampleFile.doc

每当我运行代码时,控制台都会返回以下内容:“重命名项目:无法将参数绑定到参数‘NewName’,因为它是一个空字符串。”

有谁知道问题出在哪里?

提前感谢您的帮助!

$files = get-childitem -path "C:\XXXX\XXXX\XXXX" -Recurse 
foreach($file in $files) {

    if($file.Name -match ".") {
        $newName = $file.Name -ireplace (".", "")
        Rename-Item $file.FullName $newName
        Write-Host "Renamed" $file.Name "to $newName at Location:" $file.FullName
    }
}

【问题讨论】:

    标签: powershell


    【解决方案1】:

    $file.Name -ireplace (".", "")

    总是返回一个空字符串,因为-replace operator-ireplace只是一个别名[1])对@进行操作987654322@(正则表达式),其中元字符.匹配任何字符[2]

    由于-replace 总是替换它找到的 all 匹配项,输入中的所有字符都被替换为空字符串,总体上产生一个空字符串,并通过 $newName 将一个空字符串传递给(位置暗示)Rename-Item-NewName 参数可预见地会导致您看到的错误消息。

    匹配正则表达式中的. 字符逐字,您必须将其转义为\.

    $file.Name -replace '\.', '' # Note: no (...) needed; `, ''` optional
    

    请注意,对于要逐字使用的正则表达式和字符串文字,通常最好使用 '...' 引用而不是 "..."

    但是:

    • 这也会删除. 字符。在文件名扩展名中,这是不受欢迎的。

    • 此外,您的命令可以简化,如下面的解决方案所示。


    简洁的单管道解决方案

    Get-ChildItem -File -Path "C:\XXXX\XXXX\XXXX" -Recurse -Include *.*.* | 
      Rename-Item -NewName { ($_.BaseName -replace '\.') + $_.Extension } -WhatIf
    

    注意:上面命令中的-WhatIf common parameter预览操作。一旦您确定该操作将执行您想要的操作,请删除 -WhatIf

    • -File 限制匹配文件(不包括目录)。

    • -Include *.*.* 限制匹配至少包含 2 . 字符的文件名。

    • 通过管道将文件直接从Get-ChildItem 重命名为Rename-Item 允许您将-NewName 参数指定为delay-bind script block ({ ... }),它可以从名称中动态派生新名称使用从Get-ChildItem 接收到的System.IO.FileInfo 实例的属性,分别输入文件的属性。

    • $_.BaseName -replace '\.' 删除所有文字 . 字符。 (在-replace operator 操作的regex(正则表达式)的上下文中转义为\.)来自文件base 名称(没有(最后一个)文件名的部分扩展名)。

      • 注意:不指定替换操作数等同于指定'',空字符串,导致匹配字符串被有效移除;换句话说:... -replace '\.'... -replace '\.', '' 相同
    • + $_.Extension 将原始扩展名附加到修改后的基本名称。


    [1] -replace 默认情况下不区分大小写,就像所有 PowerShell 运算符一样; -ireplace 只是明确说明了这一事实;还有-creplace 变体,其中c 表示操作区分大小写

    [2] 在 单行 字符串中;在多行字符串中,. 默认不匹配\n(换行符),尽管这可以通过正则表达式开头的内联匹配选项(?s) 进行更改。支持>

    【讨论】:

      【解决方案2】:

      关于字符串替换的一件事:当我在不转义句点的情况下尝试您的示例时,它没有替换任何内容并且没有返回任何内容(空字符串),我相信这可以回答您的“无法将参数绑定到参数'NewName',因为它是一个空字符串”

      这通过转义期间起作用。此外,它可以带括号也可以不带括号。

      $string = "the.file.name"
      
      $newstring = $string -ireplace "\.", ""
      // output: thefilename
      $newstring.length
      // output: 11
      
      $othernewstring = $string -ireplace ("\.", "")
      // output: thefilename
      $othernewstring.length
      // output: 11
      
      // What the OP tried
      $donothingstring = $string -ireplace (".", "")
      // output:
      $donothingstring.length
      // output: 0
      

      这里有一些关于字符串替换的附加信息,仅供参考https://vexx32.github.io/2019/03/20/PowerShell-Replace-Operator/

      【讨论】:

      • 这里的关键是-match-replace操作符支持regex,你需要像句点一样转义元字符。
      【解决方案3】:

      这里还有一些其他问题。您应该通过包含-File 开关过滤您的Get-ChildItem 结果以仅返回文件。

      您当前的脚本将替换最后一个 .在您的文件扩展名之前,这会导致一些问题。您需要使用$File.BaseName$File.Extension 属性来解决此问题。

      .replace() 方法替换-ireplace

      最后,您需要在 If 语句中使用 -like 条件。 -match 条件用于正则表达式,在此处无法正常工作。

      $files = get-childitem -Recurse -File 
      foreach($file in $files) {
      
          if($file.BaseName -like "*.*") {
              $newName = $file.BaseName.Replace(".","") + $file.Extension
              Rename-Item $file.FullName $newName
              Write-Host "Renamed" $file.Name "to $newName at Location:" $file.FullName
          }
      }
      

      【讨论】:

      • 放弃对一个点的测试并在所有文件名上使用.Replace('.', '') 方法会更干净吗?如果没有要替换的点,该方法将根本无济于事……这可能不是很明显 enuf,寿。 [皱眉]我拿不定主意。
      【解决方案4】:

      这是另一个利用 PowerShell 管道的解决方案(在您测试了哪些文件将被重命名后删除 -WhatIf)。

      它还使用lookahead regular expression 替换文件名中除最后一个点之外的所有点。

      Get-ChildItem -Recurse  `
          <# Only select files that have more than one '.' in their name #> `
          | Where-Object { ($_.Name.ToCharArray() | Where-Object {$_ -eq '.'} | Measure-Object ).Count -gt 1 } `
          `
          <# Change the location to the directory and rename so you don't have deal with the directory name #> `
          <# Also, use a lookahead regex to replace all but the last dot. #> `
          | ForEach-Object { Push-Location $_.Directory; Rename-Item $_ ($_.Name -replace "\.(?=.*?\.)", "") -Verbose -WhatIf; Pop-Location }
      

      这是使用别名的相同命令的更简洁版本:

      dir -r | ?{ ($_.Name.ToCharArray() | ?{ $_ -eq '.' } | measure ).Count -gt 1 } | %{ pushd $_.Directory; ren $_ ($_.Name -replace "\.(?=.*?\.)", "") -v -wh; popd }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-12
        • 1970-01-01
        • 1970-01-01
        • 2015-10-01
        • 1970-01-01
        • 2014-09-14
        • 2013-05-03
        • 2015-02-15
        相关资源
        最近更新 更多