英文:
handling the spaces of file paths in batch file that read out from a file
问题
我正在读取文件路径,通过文件paths.lst的for循环,并在特定的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 %%iwithfor /f "delims=" %%iso as to read each whole line (otherwise the default delimiters are tab and space) - replace
call :$change %%iwithcall :$change "%%i"so as to pass quoted filenames to your subroutine - within the subroutine you might need to replace
%1with"%~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 上下文中,这两个值是等效的("字符在正则表达式中不需要转义,尽管转义它们也没有害处),但这是需要注意的事项。
- 恰巧在通过 PowerShell
-
避免引号和转义问题的简单方法是依赖于
cmd.exe的变量(使用set创建)也必然是 环境 变量,因此 PowerShell 也会继承它们;例如,通过$env:fold可以在 PowerShell 代码中访问fold(%fold%) 的值。这种间接方式引用值可以稳健地访问其原样值。 -
然后,您可以专注于设置变量值,而无需使用
'...''引号来使 PowerShell 受益。- 在
cmd.exeSET语句中设置任意值的最稳健方法是 总体上 将名称、=和值括在"..."中;例如,要使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 asC:\Users\ect\doc doc\test dir\conf\{testdir1}\test.xmlis not taken literally if used unquoted as a command argument in PowerShell code.- Therefore,
gc %filePath%will fail with such paths.
- Therefore,
-
PowerShell's initial command-line parsing removes the
\from\"sequences, so that'Value=\"0\"'is seen as verbatim'Value="0"'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'...'string literal, these two values are equivalent ("chars. don't require escaping in regexes, though escaping them does no harm), but it is something to be aware of.
- It just so happens that in the context of a regex (as used by
-
A simple way to avoid quoting and escaping headaches is to rely on the fact that
cmd.exe's variables (created withset) are invariably also environment variables, which PowerShell therefore inherits; e.g., the value offold(%fold%) can be accessed via$env:foldin 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
'...'quoting for the benefit of PowerShell.- The most robust way to set arbitrary values in a
cmd.exeSETstatement is to enclose the name,=, and value in"..."overall; e.g., to makefoldcontain verbatimValue=\"0\", useset "fold=Value=\"0\"" - As noted, the
~in%~1removes any enclosing"that are part of the value, so thatset "filePath=%~1"robustly stores the unquoted path infilePath.
- The most robust way to set arbitrary values in a
To put it all together:
@echo off & setlocal
:: Note the "delims=" and the %%i enclosed in "..."
for /f "delims=" %%i in (paths.lst) do call :$change "%%i"
goto :EOF
:$change
:: Note the "..." around the name, "=", and the value *overall*.
:: No need for '...' quoting.
set "filePath=%~1"
set "fold=Value=\"0\""
set "fnew=Value=\"1\""
:: Note the $env: references to the variables defined above.
powershell -Command "(gc $env:filePath) -replace $env:fold, $env:fnew | Out-File $env:filePath -encoding utf8"
echo Value changed for: "%filePath%"
goto :EOF
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论