2017-02-09 241 views
2

我试图使用PowerShell批量复制和重命名文件。使用PowerShell批量复制和重命名文件

原始文件被命名为AAA001A.jpg,AAB002A.jpg,AAB003A.jpg等

我想这些文件使用新名称复制,从文件名剥离前四个字符,并在这段时间之前的字符,以便复制的文件被命名为01.jpg,02.jpg,03.jpg等。

我在Linux上有Bash脚本的经验,但我很难过如何做到这一点与PowerShell。

Get-ChildItem AAB002A.jpg | foreach { copy-item $_ "$_.name.replace ("AAB","")" } 

(它不工作)

+0

您可以从颜色看在你的' “$ _ name.replace(” AAB “ ”“)”',它不是明智的处理,它会需要更像'$ _。name.replace(“AAB”,“”)' - 不在内部字符串引号内,或者“$ {$ _。name.replace(”AAB“,”“)}”'里面字符串引号。 – TessellatingHeckler

+1

@TessellatingHeckler:除了您在双引号字符串内而不是'$ {...}'的意思是'$(...)'(子表达式运算符)以外,很好的一点。 – mklement0

回答

0

注:
*虽然可能略超过abelenky's answer比较复杂,(a)是它更加坚固确保只处理符合所需模式的*.jpg文件,(b)显示一些高级正则表达式技术,(c)提供背景信息并用OP方法解释问题。
*本答案使用PSv3 +语法。

Get-ChildItem *.jpg | 
    Where-Object Name -match '^.{4}(.+).\.(.+)$' | 
    Copy-Item -Destination { $Matches.1 + '.' + $Matches.2 } -WhatIf 

保留命令短,目标目录中并没有明确的控制,所以副本将被放置在当前目录。确保放置在相同的目录中。作为输入文件,使用
Join-Path $_.PSParentPath ($Matches.1 + '.' + $Matches.2)内部{ ... }

-WhatIf预览哪些文件会被复制到;将其删除以执行实际的复制。

  • Get-ChildItem *.jpg输出所有*.jpg文件 - 无论他们是否适合文件的方式进行重命名。

  • Where-Object Name -match '^.{4}(.*).\.(.+)$'然后缩小了匹配向下那些符合该图案,使用正则表达式(正则表达式):

    • ^...$锚正则表达式,以确保它的整个输入相匹配( ^匹配输入的开始,并且$结束)。
    • .{4}匹配第一个4个字符(.),无论它们是什么。
    • (.+)匹配任何字符非空序列,并且由于被封入(...),捕获在捕获组,这反映在自动$Matches变量的序列,如$Matches.1访问的(由于是第一个捕获组) 。
    • .匹配文件扩展名之前的字符。
    • \.匹配文字.,由于以\转义 - 即扩展的开始。
    • (.+)是捕获文件扩展名(不含前面的.文字)的第2个捕获组,可以被访问为$Matches.2
  • Copy-Item -Destination { $Matches.1 + '.' + $Matches.2 }然后根据从输入文件名提取的捕获组值来重命名每个输入文件。

    • 通常,直接输送至一个小命令,如果可行的话,始终是最好管道传递到小命令Foreach-Object(其内置别名是foreach),出于性能原因。
      在上面的Copy-Item命令中,目标路径是通过脚本块参数指定的,对每个输入路径使用绑定到输入文件的$_进行评估。

    • 注:上述假定副本应放置在当前目录,因为脚本块输出一个单纯文件名,而不是一个路径

      • 要明确控制目标路径,请在-Destination脚本块中使用Join-Path
        例如,要确保副本始终放置在与输入文件相同的文件夹中 - 与当前目录无关。是 - 使用:
        Join-Path $_.PSParentPath ($Matches.1 + '.' + $Matches.2)

至于你已经试过

  • "..."(双引号字符串),您必须使用$(...)子表达式运算符,以便嵌入应该用其值替换的表达式。

  • 无论如何,.replace ("AAB", "")(a)由于空格字符而在语法上断开。 (之前(你迷惑[string]类型的.Replace()方法使用PowerShell的-replace操作?),(B)硬编码的前缀去掉,(c)是有限的,以字符,和(d)没有按”在这段时间之前删除角色。

  • 目的地位置的警告也适用:如果你的表达式的工作,那就只能评估到,这将把生成的文件中当前目录,而不是同一个目录中输入文件(尽管如此,如果您从当前目录运行命令,或者如果这是您的实际意图,这不会成为问题)。

+0

谢谢!你的答案奏效。 PowerShell的正则表达式不符合POSIX标准。你能推荐PowerShell的学习资源吗? – oavaldezi

+0

PowerShell基于.NET Framework,所以它的正则表达式比POSIX的要求强大得多(这通常是件好事)。至于学习:或许[this](https://www.simple-talk。com/sysadmin/powershell/powershell-one-liners-variables,-parameters,-properties,-and-objects /)是有帮助的,但我也建议熟悉PowerShell自己的帮助系统 - 参见['Get-Help Get-Help '](https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.core/get-help)。 – mklement0

+0

与一些简单的SubString/Concatenation操作相比,该正则表达式仍然显得很丑陋。 – abelenky

0

不是PowerShell中,但批处理文件:

一对夫妇的试验和错误小时后,当我收到这是接近

(因为有人想成为超迂腐有关评论)

@echo off 
setlocal enabledelayedexpansion 
for %%a in (*.jpg) do ( 
    ::Save the Extension 
    set EXT=%%~xa 

    ::Get the Source Filename (no extension) 
    set SRC_FILE=%%~na 

    ::Chop the first 4 chars 
    set DST_FILE=!SRC_FILE:~4! 

    ::Chop the last 1 char. 
    set DST_FILE=!DST_FILE:~,-1! 

    :: Copy the file 
    copy !SRC_FILE!!EXT! !DST_FILE!!EXT!) 
+0

警告(可能会也可能不是问题):如果碰巧存在基本名称中少于5个或更少字符的'* .jpg'文件,则会导致问题。 尝试使用'??????? *。jpg'来限制与* .jpg文件的匹配,例如7+个字符。在基本名称中,但这不是一个解决方案 - 令人惊讶的是,该模式还将'* .jpg'文件与_fewer_chars匹配。在基地名称。 – mklement0

+0

只是对不熟悉批处理文件语法的读者的提示:在'(...)'块中使用'::'注释通常只能在有限的场景和[规则](http:// stackoverflow。 com/a/42148114/45375)很难记住。相比之下,使用'REM'是安全的。 – mklement0

-1

在PowerShell中:
(没有讨厌的正则表达式。我们讨厌正则表达式!我们所做的)上表达

Get-ChildItem *.jpg | Copy-Item -Destination {($_.BaseName.Substring(4) -replace ".$")+$_.Extension} -WhatIf 

!详细说明:

$_.BaseName.Substring(4) :: Chop the first 4 letters of the filename. 
-replace ".$"    :: Chop the last letter. 
+$_.Extension    :: Append the Extension 
+0

警告(可能会也可能不是问题):'.Substring()'调用将打破基本名称少于4个字符的文件名。 – mklement0

+0

这是海报问题。他的问题意味着文件名足够长。 – abelenky

+1

我看到你已经与魔鬼达成了一个小协议 - 顺势疗法剂量的正则表达式('。$')。 我很高兴陪练导致更好的答案。请问你的驴子。 – mklement0

-1

试试这个:

Get-ChildItem "C:\temp\Test" -file -filter "*.jpg" | where BaseName -match '.{4,}' | 
    %{ Copy-Item $_.FullName (Join-Path $_.Directory ("{0}{1}" -f $_.BaseName.Substring(4, $_.BaseName.Length - 5), $_.Extension)) } 
相关问题