我从这条路开始:
D:\starting\path
该路径有子文件夹:
D:\starting\path\sub\01
D:\starting\path\sub\02
和文件:
D:\starting\path\sub\01\fileA.txt
D:\starting\path\sub\01\fileB.txt
最终,我希望文件将起始文件夹下的文件夹合并到其文件名中。即:
D:\starting\path\sub\01\fileA (sub-01).txt
D:\starting\path\sub\02\fileB (sub-02).txt
我尝试了以下单行脚本,但没有成功。
D:\starting\path> $startPath=(Get-Location); $startPath=($startPath -replace "\\","\\"); $startPath=($startPath+"\\"); Get-ChildItem -file -recurse | foreach-object {$currentPath=($_.Directory.ToString() -replace "\\","\\"); $append=((($currentPath -replace "${startPath}","") -replace "\\\\","-")); $append=(" ("+$append+")"); $new=($_.directory.ToString()+"\"+$_.BaseName+$append+$_.extension); echo $_.fullname $new}
注意:上面的一行代码已从原始代码更新为$append=((($_.directory -replace "${startPath}","") -replace "\\","-"));
。$currentPath=($_.Directory.ToString() -replace "\\","\\"); $append=((($currentPath -replace "${startPath}","") -replace "\\\\","-"));
原始$_.directory -replace ...
代码中的 未能将其转换为字符串,然后将单反斜杠更改为双反斜杠。这本身会产生问题,但并不能解决原始问题。
该脚本返回以下输出:
D:\starting\path\sub\01\fileA (D:-starting-path-sub-01).txt
D:\starting\path\sub\02\fileB (D:-starting-path-sub-02).txt
问题显然出在第一个问题上,-replace
但我不知道为什么。这显然与路径D:\starting\path
在变量中而不是手动输入字符串有关。存储在字符串中的路径有什么特别之处会导致这种情况?我也尝试过同样的脚本,只是我删除了$startPath=($startPath -replace "\\","\\");
感谢您的指导。
注意:echo $_.fullname $new
最终会是这样mv $_ $new
,但我在测试期间使用 echo。
更新
块形式的脚本(进行了小更新和一次修复...但并未解决原始问题)
# Assume
# D:\start\path
$startPath=(Get-Location) # D:\start\path
$startPath=($startPath -replace "\\","\\") # D:\\start\\path
$startPath=($startPath+"\\") # D:\\start\\path\\
Get-ChildItem -recurse | foreach-object {
$currentPath=(($_.directory.ToString()) -replace "\\","\\")
$append=((($currentPath -replace "${startPath}","") -replace "\\\\","-"))
# first replace D:\\start\\path\\sub\\01 --> sub\\01 (THIS ISN'T HAPPENING)
# second replace sub\\01 --> sub-01
$append=(" ("+$append+")")
$new=($_.directory.ToString()+"\"+$_.BaseName+$append+$_.extension)
echo $_.fullname $new
}
中的$currentPath
和变量返回预期的字符串。也就是说,和。为什么没有用中的替换还不清楚。$startPath
$append=((($currentPath -replace "${startPath}","") -replace "\\\\","-"))
$currentPath: D:\\start\\path\\sub\\01
$startPath: D:\\start\\path\\
$startPath
""
$currentPath
答案1
使用有条件的逻辑以便更好地控制并避免空命令参数错误。不要使用-replace
并只加入使用索引值将最后两个文件夹与拆分文件夹放在一起[-1..-2]
。
使用连字符 将两个文件夹重新连接在一起-
。使用子表达式运算符将变量创建$append
为字符串并用括号将其包裹起来。
现在将其连接到基本文件名末尾扩展名之前的文件名。
电源外壳
$startPath = (Get-Location);
$startPath = "$($startPath.Split("\") -join "\\")\\";
Get-ChildItem $startPath -recurse | % { Process {
If( $_.directory ) { $currentPath = $(($_.directory.ToString()).Replace("\\","\\"))};
$append = "($($currentPath.Split("\")[-1..-2] -join "-"))";
$new = If( $_.directory ) { ( "$($_.directory.ToString())\$($_.BaseName)$append$($_.extension)" ) };
echo $_.fullname $new
}};
支持资源
- ForEach 对象
标准别名对于 Foreach 对象:'
%
' 符号,ForEach - 如果()
- 分裂()
- -加入
- PowerShell 运算符 $( ) @( ) :: &
答案2
继续我的评论。
对于 ISE 或 VSCode 中的故障排除:
这...
$startPath=(Get-Location); $startPath=($startPath -replace "\\","\\"); $startPath=($startPath+"\\"); Get-ChildItem -recurse | foreach-object {$append=((($_.directory -replace "${startPath}","") -replace "\\","-")); $append=(" ("+$append+")"); $new=($_.directory.ToString()+"\"+$_.BaseName+$append+$_.extension); echo $_.fullname $new}
...变成了这样...
$startPath = 'D:\Temp'
$startPath = ($startPath -replace "\\","\\")
$startPath = ($startPath+"\\")
Get-ChildItem -recurse |
foreach-object {
$append = (
(
($_.directory -replace "${startPath}","") -replace
"\\","-"
)
)
$append = (" ("+$append+")")
$new = ($_.directory.ToString()+"\"+$_.BaseName+$append+$_.extension)
echo $_.fullname $new}
...所有不好的东西立即就显现出来,然后你逐步完成它,这就是你所追求的(真正的一句话):
Get-ChildItem -Path (Read-Host -Prompt 'Enter a starting path') -File -Recurse |
Select-Object -First 9 |
foreach-object {"$($PSItem.BaseName) - $($PSItem.Directory)$($PSItem.Extension)"}
# Results
<#
abc - Copy - Copy - D:\temp.bat
abc - Copy - D:\temp.bat
abc - D:\temp.bat
about_Redirection Microsoft Docs - D:\temp.url
aes - D:\temp.key
available13.html.2019-03-26_081523 - D:\temp.bak
#>
注意事项:
从程序角度来说,目录、文件名、变量名、属性名等中的特殊字符、空格从长远来看是一个非常糟糕的想法。
对于你继承的或已经存在的东西,我们都必须处理,但对于你控制或可以操纵的东西,嗯,你知道的。
答案3
我终于猜到你想要什么了,我从头开始写了一个脚本,我还没有测试它,因为我现在不能使用电脑,但它应该可以做你想要的:
$startdir=Read-Host "Please input starting path"
$files=(Get-ChildItem -Path $startdir -File -Force -Recurse).FullName
foreach ($file in $files) {
$directories=(Split-Path -Path $file -Parent).split("\")
$parent=$directories | Select-Object -Last 1
$grandparent=$directories | Select-Object -Index $($directories.count - 2)
$name=[System.IO.Path]::GetFileNameWithoutExtension($file)
$extension=$file.split(".") | Select-Object -Last 1
Rename-Item -Path $file -NewName $($name+" ("+$grandparent+"-"+$parent+")."+$extension)
}
保存为 .ps1 文件,它会给你你想要的内容。
答案4
我终于可以读懂 OP 的代码了,并且知道了它为什么不起作用。
首先,第二、三、五行代码是不必要的,应该删除
其次,-replace 运算符使用正则表达式匹配,因此我们需要使用双反斜杠来表示文字反斜杠,但是这里我们并不尝试进行正则表达式匹配(起始目录只有一个可能的匹配值),所以最好使用 .replace() 方法。
第三,Get-Location cmdlet 要求您先 Set-Location,最好使用 Read-Host,这样您就可以处理任何位置,而无需先更改目录。
固定代码:
$startPath=Read-Host "Please input start path" # Input D:\Start\Path\
Get-ChildItem -path $startPath -file -force -recurse | foreach-object {
$append=" ("+$_.directory.ToString().replace($startPath).replace("\","-")+")"
$new=($_.directory.ToString()+"\"+$_.BaseName+$append+$_.extension)
echo $_.fullname $new
}
尝试固定代码,我还没有测试过,因为我目前无法这样做,所以请测试它并告诉我结果,以便我可以进一步改进它,但我认为它应该可以工作。
保存为 .ps1 文件(例如 script.ps1)并 cd(或 sl)到其位置并使用 .\script.ps1 之类的命令来调用它。
受到这个答案的启发https://superuser.com/a/1625400/1250181之后,我进一步改进了我的代码:
$startPath=Read-Host "Please input start path" # Input D:\Start\Path\
Get-ChildItem -path $startPath -file -force -recurse | foreach-object {
$append=" ("+$($_.directory.ToString().Split("\")[-1..-2] -join "-")+")"
$new=($_.directory.ToString()+"\"+$_.BaseName+$append+$_.extension)
echo $_.fullname $new
}