【问题标题】:Renaming files in a directory with a list in Text file使用文本文件中的列表重命名目录中的文件
【发布时间】:2020-07-03 07:30:52
【问题描述】:

我有一个包含数千个文件的文件夹,但我没有这些文件的名称列表。它们只是随机的。

asd.wav
faf.wav
gwa.wav

我有一个包含文件名的 FileNames.txt:

1A
2
3
4B

我只想按照 txt 文件中的文件名顺序重命名我的文件。 txt 中的行数可多可少。当涉及到行尾时,它应该停止重命名。该怎么做?

【问题讨论】:

    标签: bash powershell shell command-line terminal


    【解决方案1】:

    PowerShell 解决方案:

    PowerShell 7+ 解决方案

    [Linq.Enumerable]::Zip(
      [string[]] (Get-ChildItem . -File).FullName,
      [string[]] (Get-Content FileNames.txt) 
    ) | Rename-Item -LiteralPath { $_.Item1 } -NewName { $_.Item2 } -WhatIf 
    

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

    以上使用.来定位当前目录下的文件;根据需要进行调整。

    System.Linq.Enumerable.Zip 方法允许方便地枚举集合元素的,作为 2 元素元组;请注意,必须使用强制类型转换 ([string[]]) 显式键入参数,以便 PowerShell 正确解析方法调用;一般来说,请注意,从 7.0 开始,PowerShell 缺乏对 .NET 扩展方法的支持(这需要在此处显式使用 [System.Linq.Enumerable])和对调用通用方法的全面支持,尽管 GitHub 上有功能请求 - 请参阅 herehere

    这些元组通过管道传送到Rename-Item,其参数通过delay-bind script blocks 绑定以动态访问每个输入元组的属性。


    PowerShell 6- 解决方案:

    # Read the array of lines == new file names from FileNames.txt
    $names = Get-Content FileNames.txt
    
    # Get as many files as new file names; '.' targets the current directory;
    # Adapt as needed.
    $files = (Get-ChildItem . -File)[0..($names.Count-1)] 
    
    # Perform the renaming.
    $i = 0
    $files | Rename-Item -NewName { $names[$script:i++] } -WhatIf 
    

    注意:$i 变量在延迟绑定脚本块 ({ ... }) 中称为 $script:i,因为脚本块在 范围内运行。 要使其在父作用域也不是脚本作用域的情况下也能正常工作,请使用(Get-Variable -Scope 1 i).Value++ 而不是$script:i++

    【讨论】:

      【解决方案2】:

      我已经制定了另一个 PowerShell 脚本:

      在当前工作目录 ./ 中,我们创建一个名为 ./renamedir1.ps1 的脚本。 我们有一个子目录./subdir2handle,新的文件名列表在文件中 ./fileslist.txt.

      这样安排可以避免影响文件renamedir1.ps1和fileslist.txt本身。

      renamedir1.ps1在这里:

      #
      # define some vars:
      #
      $myDir2Handle = "subdir2handle"
      $myFilesList = "fileslist.txt"
      
      #
      # get files list in dir subdir2handle:
      #
      $xarr = (Get-ChildItem $myDir2Handle).name
      $nx = $xarr.length
      
      #
      # get list file content in another array:
      #
      $yarr = Get-Content $myFilesList
      $ny = $yarr.length
      #$yarr[0]
      #exit(0);
      
      #
      # get minimum of the 2 lengths:
      #
      $nMin = [math]::min($nx, $ny)
      
      #
      # rename items:
      #
      for($i = 0; $i -lt $nMin; $i++) {
          Write-Host Rename $xarr[$i]
          Move-Item ($myDir2Handle + "/" + $xarr[$i]) ($myDir2Handle + "/" + $yarr[$i])
      }
      

      在 Windows 中,我们通过以下方式调用脚本:

      .\renamedir1.ps1
      

      【讨论】:

        【解决方案3】:

        这是一个 bash 答案:

        ls  | paste - FileNames.txt   | awk 'NF == 2 { print "mv ", $1, $2 } ' | bash
        

        说实话,这个解决方案有点危险 - 文件名中的空格(在 FileNames.txt 或目录中)会导致问题。

        这是一个更强大的版本,它可以处理带有$ 的空格甚至文件名:

        awk ' 
          FNR == NR { filename[ ++count ] = $0 ;  next }
          count > 0 { printf( "mv '"'%s' '%s'"'\n", $0, filename[ count-- ])  } 
        ' FileNames.txt <( ls )  | bash
        

        【讨论】:

          【解决方案4】:

          我是这样做的:

          $FileNo = 0
          $date = (get-date).ToString('yyyyMMdd')
          Get-ChildItem -LiteralPath 'C:\YourFilePath\' -File | ForEach-Object {
                  $_ | Rename-Item -NewName { "something" + $date + "_" + $FileNo + ($_.Extension) }
                  $FileNo++
              }
          

          对于计数器,您可以读出文件/csv 并添加一个计数器以跳过行(您也可以省略日期,这只是我添加的内容)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-11-08
            • 2023-03-19
            • 2020-04-19
            • 1970-01-01
            • 2012-01-17
            • 2015-08-02
            • 1970-01-01
            • 2020-08-30
            相关资源
            最近更新 更多