gpt4 book ai didi

批处理文件中的 Powershell - 如何转义元字符?

转载 作者:行者123 更新时间:2023-12-04 20:31:18 29 4
gpt4 key购买 nike

运行 Windows 7,当我 复制文件 到外部磁盘,在例程中 文件备份 ,我使用 Powershell v2(从批处理文件运行)在副本文件上重新创建原始文件的所有时间戳。

以下代码在大多数情况下都能成功运行,但并非总是如此:-

SET file=%1
SET dest=E:\

COPY /V /Y %file% "%dest%"

SetLocal EnableDelayedExpansion
FOR /F "usebackq delims==" %%A IN ('%file%') DO (
SET fpath=%%~dpA
SET fname=%%~nxA
)

PowerShell.exe (Get-Item \"%dest%\%fname%\").CreationTime=$(Get-Item \"%fpath%%fname%\" ^| Select-Object -ExpandProperty CreationTime ^| Get-Date -f \"MM-dd-yyyy HH:mm:ss\")

当我将源文件拖放到批处理文件时,上面的代码复制文件,然后将复制(目标)文件的创建日期/时间设置为源文件的创建日期/时间。

但是在某些情况下代码会失败。如果文件名包含“毒药”字符,例如(例如) 方括号 [...],它给出了错误“在此对象上找不到属性 'CreationTime'”。文件名的解析显然在“毒药”字符处失败。

代码做 不是 使用诸如 之类的符号给出错误& .

我尝试了使用单引号和双引号转义 Powershell 命令的大量变体,但没有成功。请有人告诉我如何转义 Powershell 反对的那些字符。

这只是更长的批处理例程的一小部分,我依靠它进行常规系统备份。我没有切换到 .ps1 文件的选项,所以我需要一个在批处理文件中工作的解决方案,而不是在 .ps1 文件中。

感谢您的所有建议。

附录 :我通过采纳 mklement0 提供的一个建议找到了一个解决方案。通过将以下命令替换为我原来的 Powershell 命令,我的方括号问题得到了解决 -
PowerShell.exe (Get-Item -LiteralPath \"%dest%\%fname%\").CreationTime=$(Get-Item -LiteralPath \"%fpath%%fname%\" ^| Select-Object -ExpandProperty CreationTime ^| Get-Date -f \"MM-dd-yyyy HH:mm:ss\")

为了将来引用,请注意(在 Windows 7 上):
  • 使用这个修改后的命令成功地保留了任何额外的空白字符。没有必要包含一对额外的双引号字符来实现这一点。
  • 编者注:这是一个边缘情况,但值得指出的是:如果没有额外的双引号,任何超过一个空格的运行都会被折叠成一个空格;例如。,powershell.exe -command echo \"a b\" yield a b .
    将整个命令包含在 "..." 中原则上有帮助 -powershell.exe -command "echo \"a b\"" - 但自从 cmd.exe然后不将整个字符串识别为单个双引号字符串,元字符可能会破坏命令;例如。,powershell.exe -command "echo \"a & b\""
  • 不是 文件路径可能包含任何 "(双引号)字符,因此不需要代码来转义该字符。双引号字符是 FAT 和 NTFS 文件系统中的非法字符,因此在文件路径中永远不会遇到。
  • 在 Powershell 命令中使用 '(单引号)原则上是不好的,因为该字符在 NTFS 文件系统中不是非法的,因此可以在文件的实际路径中找到。必须优先使用双引号,因为在实际的 NTFS 路径中永远不会遇到非法的双引号字符。
  • 使用 ROBOCOPY,以下通配符解决方案即使使用大多数有害字符也能成功 - 除 之外的所有字符! (即它可以处理 = & ` ^ )。即使有多个有毒字符(尽管不是万无一失),此命令也非常强大:
    ROBOCOPY "%fpath% " "%dest%" "*%name%*%ext%*" /B /COPY:DAT /XJ /SL /R:0 /W:0 /V
    一种。 “%fpath%”中的空格是必不可少的,这不是错误。

    湾在所有情况下唯一致命的有毒字符是感叹号 (!)。

    C。毒字符似乎只是文件名中的问题,而不是路径中的问题。
  • 最佳答案

    第一件事:

    在 Windows 7 中,您可以使用 robocopy.exe复制文件,默认情况下会保留时间戳(并且可以选择让您详细控制复制哪些属性):

    @echo off
    :: Do NOT use setlocal ENABLEDELAYEDEXPANSION, because it would cause
    :: misinterpretation of "!" chars. in filenames.
    setlocal

    :: Parse the file path given as %1 (the first argument) into its folder path and filename.
    :: Be sure to pass the %1 argument *double-quoted* to prevent up-front interpretation
    :: by cmd.exe; e.g.:
    :: someBatchFile "c:\tmp\foo.txt" or someBatchFile "%file%"
    :: Note that %~dp1 always returns a path with a trailing "\".
    set "fpath=%~dp1"
    set "fname=%~nx1"

    :: Determine the destination folder
    set "dest=E:\"

    :: Use robocopy to copy the file to the destination dir. with timestamps preserved.
    :: Syntax is: <source-dir> <dest-dir> <filename-or-wildcard> ...
    :: IMPORTANT: To avoid problems with paths that end in "\", always follow
    :: a variable reference inside "..." with a *space* (a trick discovered by
    :: Ed999 himself).
    robocopy "%fpath% " "%dest% " "%fname%"

    笔记:
  • 虽然 robocopy主要用于复制整个目录,它允许您通过从第三个位置参数开始指定的通配符表达式复制单个文件,如 "%fname%"以上。
    鉴于 robocopy - 与 PowerShell 不同 - 不考虑 []通配符metacharacters ,这种方法应该有效(如果你的文件名包含嵌入的 *? 字符,你只会有问题,这不太可能)。
  • 尾随空格技巧(例如, "%fpath% " )是必要的,因为 robocopy - 与大多数命令行实用程序一样 - 处理 \"在参数结束时作为转义 " ,这会破坏命令。严格来说,正确的解决方法是将尾随 \ 加倍。 (例如, "E:\\" ),但是您可以通过附加一个空格而逃脱,因为路径中的任何尾随空格都将被忽略。因此,使此类调用健壮的一种简单方法是始终使用 "%var% " (结束双引号前的尾随空格)传递文件夹路径时。
  • robocopy没有类似于 /V 的开关这会导致它验证文件是否被正确复制,但是 - 至少根据 this blog post - 运行 verify on事先应该有同样的效果。


  • 如果您仍然需要通过 PowerShell 复制创建时间戳:
    powershell -command "(Get-Item -LiteralPath '%dest%%fname%').CreationTime=(Get-Item -LiteralPath '%fpath%%fname%').CreationTime"

    警告:如果您的文件名有可能嵌入 '字符。 (单引号/撇号),您必须首先将它们转义,通过将它们加倍(例如, %fname:'=''% 返回 %fname% 的值,所有 ' 实例都加倍):
    powershell -command "(Get-Item -LiteralPath '%dest:'=''%%fname:'=''%').CreationTime=(Get-Item -LiteralPath '%fpath:'=''%%fname:'=''%').CreationTime"
  • 请注意,整个命令包含在 "..." 中。 ,以免cmd.exe可能包含在变量值中的元字符(例如 &),以免破坏命令。[1]
  • 在命令字符串中,'...'用于确保 PowerShell 将变量值视为文字(例如,如果您使用 "..." 并且文件名包含 $ ,则结果将出乎意料)。
  • -LiteralPath确保 Get-Item将文件路径解释为文字,而它是-Path当您按位置传递路径时隐含的参数,并将路径传递给-Path被解释为通配符表达式,这可能会导致 PowerShell 通配符元字符出现问题,例如 [] .
  • 无需转换.CreationTime源文件的属性值先为日期+时间字符串;您可以简单地将其直接分配给目标文件的 .CreationTime属性,类型为 [System.DateTime] .


  • [1] 引用头疼 :
  • 仅包含 \ 中的变量引用-escaped 双引号,如问题 ( \"%dest%\%fname%\" ) 中,是不够的,因为这样做会使值受到空白规范化,这意味着多个空格的运行被规范化为单个空格。
  • 同时将命令整体封装在 "..." 中原则上有帮助,cmd.exe然后不将整个字符串识别为单双引号字符串,在这种情况下,元字符如 &在变量值中可以中断命令;例如。,powershell.exe -command "echo \"a b\""工作正常,忠实地保留空白,但powershell.exe -command "echo \"a & b\""中断,由于 & .
  • 使用 \""而不是 \"解决了元字符问题,但重新引入了空白规范化:powershell.exe -command "echo \""a & b\""" yield a & b
  • 因此,使用 '...' PowerShell 字符串里面的整体"..." string 是使命令健壮的最简单方法:您只需要转义 '变量值中的实例。
  • 关于批处理文件中的 Powershell - 如何转义元字符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45666682/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com