处理从文件中读取的批处理文件路径中的空格。

huangapple go评论55阅读模式
英文:

handling the spaces of file paths in batch file that read out from a file

问题

我正在读取文件路径,通过文件paths.lstfor循环,并在特定的xml文件中查找替换的‘Value’参数。

paths.lst文件的内容如下:

C:\Users\ect\doc doc\test dir\conf\{testdir1}\test.xml
C:\Users\ect\doc doc\test dir\conf\{testdir2}\test.xml
C:\Users\ect\docdoc\testdir\conf\{testdir3}\test.xml
@echo off

for /f %%i in (paths.lst) do call :$change %%i
REM exit

:$change
set filePath='%1%'
echo 修改的数值为:'%filePath%'
set fold='Value=\"0\"'
set fnew='Value=\"1\"'
powershell -Command "(gc %filePath%) -replace %fold%, %fnew% | Out-File %filePath% -encoding utf8"
英文:

I am reading the path of files over a file paths.lst in a for loop and looking for a 'Value' parameter to be replaced in particular xml files.

The content of the paths.lst file is as follows:

C:\Users\ect\doc doc\test dir\conf\{testdir1}\test.xml
C:\Users\ect\doc doc\test dir\conf\{testdir2}\test.xml
C:\Users\ect\docdoc\testdir\conf\{testdir3}\test.xml
@echo off

for /f %%i in (paths.lst) do call :$change %%i
REM exit

:$change
set filePath='%1'
echo Value changed for:'%filePath%'
set fold='Value=\"0\"'
set fnew='Value=\"1\"'
powershell -Command "(gc %filePath%) -replace %fold%, %fnew% | Out-File %filePath% -encoding utf8"

The first and second paths can not be read out, due to empty spaces, but the script works for the third path C:\Users\ect\docdoc\testdir\conf\{testdir3}\test.xml

答案1

得分: 2

  • for /f "delims=" %%i 替换 for /f %%i 以便读取每一整行(否则默认分隔符是制表符和空格)
  • call :$change "%%i" 替换 call :$change %%i 以便将带引号的文件名传递给子例程
  • 在子例程内,你可能需要用 %1 替换成 "%~1"。带有波浪号的 ~ 可以去掉任何已存在的双引号,然后再添加新的引号。
英文:

You need to:

  • replace for /f %%i with for /f "delims=" %%i so as to read each whole line (otherwise the default delimiters are tab and space)
  • replace call :$change %%i with call :$change "%%i" so as to pass quoted filenames to your subroutine
  • within the subroutine you might need to replace %1 with "%~1". With the tilde you strip any double quotes if they existed, and then you add new ones.

答案2

得分: 1

Mike Nakis' 有用回答 很好地涵盖了 cmd.exe 部分的内容。

现在我来解决 PowerShell 部分的事情:

  • {} 在 PowerShell 中是 元字符,因此文件路径,如 C:\Users\ect\doc doc\test dir\conf\{testdir1}\test.xml,如果在 PowerShell 代码中未加引号使用,则 不会 被视为字面量。

    • 因此,对于这种路径,gc %filePath% 将会 失败
  • PowerShell 的初始命令行解析会从 \" 序列中 移除 \,因此当 PowerShell 代码执行时,'Value=\"0\"' 被视为原样的 `'Value="0"''。

    • 恰巧在通过 PowerShell '...'' 字符串文字指定的 regex 上下文中,这两个值是等效的(" 字符在正则表达式中不需要转义,尽管转义它们也没有害处),但这是需要注意的事项。
  • 避免引号和转义问题的简单方法是依赖于 cmd.exe 的变量(使用 set 创建)也必然是 环境 变量,因此 PowerShell 也会继承它们;例如,通过 $env:fold 可以在 PowerShell 代码中访问 fold (%fold%) 的值。这种间接方式引用值可以稳健地访问其原样值。

  • 然后,您可以专注于设置变量值,而无需使用 '...'' 引号来使 PowerShell 受益。

    • cmd.exe SET 语句中设置任意值的最稳健方法是 总体上 将名称、= 和值括在 "..." 中;例如,要使 fold 包含 原样的 Value=\"0\",请使用 set "fold=Value=\"0\""
    • 正如已指出的那样,%~1 中的 ~ 会删除值的任何包围的 ",因此 set "filePath=%~1" 稳健地将 未引用的 路径存储在 filePath 中。

综合起来:

@echo off & setlocal

:: 请注意 "delims=""..." 中的 %%i。
for /f "delims=" %%i in (paths.lst) do call :$change "%%i"
goto :EOF

:$change
  :: 请注意名称、"=" 和值的 "..." 总体上。
  :: 不需要 '...' 引号。
  set "filePath=%~1"
  set "fold=Value=\"0\""
  set "fnew=Value=\"1\""
  :: 请注意上面定义的变量的 $env: 引用。
  powershell -Command "(gc $env:filePath) -replace $env:fold, $env:fnew | Out-File $env:filePath -encoding utf8"
  echo Value changed for: "%filePath%"
goto :EOF

请注意,这是对您提供的代码的翻译。如果您有其他问题或需要进一步的帮助,请告诉我。

英文:

<!-- language-all: sh -->

Mike Nakis' helpful answer covers the cmd.exe side of things well.

Let me address the PowerShell side of things:

  • { and } are metacharacters in PowerShell, so a file path such as C:\Users\ect\doc doc\test dir\conf\{testdir1}\test.xml is not taken literally if used unquoted as a command argument in PowerShell code.

    • Therefore, gc %filePath% will fail with such paths.
  • PowerShell's initial command-line parsing removes the \ from \&quot; sequences, so that &#39;Value=\&quot;0\&quot;&#39; is seen as verbatim &#39;Value=&quot;0&quot;&#39; when the PowerShell code executes.

    • It just so happens that in the context of a regex (as used by -replace) that is specified via a PowerShell &#39;...&#39; string literal, these two values are equivalent (&quot; chars. don't require escaping in regexes, though escaping them does no harm), but it is something to be aware of.
  • A simple way to avoid quoting and escaping headaches is to rely on the fact that cmd.exe's variables (created with set) are invariably also environment variables, which PowerShell therefore inherits; e.g., the value of fold (%fold%) can be accessed via $env:fold in the PowerShell code. This indirect way of referencing the value provides robust access to its verbatim value.

  • You can then focus on setting the variable values without needing to use &#39;...&#39; quoting for the benefit of PowerShell.

    • The most robust way to set arbitrary values in a cmd.exe SET statement is to enclose the name, =, and value in &quot;...&quot; overall; e.g., to make fold contain verbatim Value=\&quot;0\&quot;, use set &quot;fold=Value=\&quot;0\&quot;&quot;
    • As noted, the ~ in %~1 removes any enclosing &quot; that are part of the value, so that set &quot;filePath=%~1&quot; robustly stores the unquoted path in filePath.

To put it all together:

@echo off &amp; setlocal

:: Note the &quot;delims=&quot; and the %%i enclosed in &quot;...&quot;
for /f &quot;delims=&quot; %%i in (paths.lst) do call :$change &quot;%%i&quot;
goto :EOF

:$change
  :: Note the &quot;...&quot; around the name, &quot;=&quot;, and the value *overall*.
  :: No need for &#39;...&#39; quoting.
  set &quot;filePath=%~1&quot;
  set &quot;fold=Value=\&quot;0\&quot;&quot;
  set &quot;fnew=Value=\&quot;1\&quot;&quot;
  :: Note the $env: references to the variables defined above.
  powershell -Command &quot;(gc $env:filePath) -replace $env:fold, $env:fnew | Out-File $env:filePath -encoding utf8&quot;
  echo Value changed for: &quot;%filePath%&quot;
goto :EOF

huangapple
  • 本文由 发表于 2023年4月13日 17:30:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76003860.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定