【问题标题】: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 上有功能请求 - 请参阅 here 和 here。
这些元组通过管道传送到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 并添加一个计数器以跳过行(您也可以省略日期,这只是我添加的内容)