PowerShell:用带有反斜杠的变量替换

PowerShell:用带有反斜杠的变量替换

我从这条路开始:

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
}};

支持资源

答案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
}

相关内容