英文:
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 %%i
withfor /f "delims=" %%i
so as to read each whole line (otherwise the default delimiters are tab and space) - replace
call :$change %%i
withcall :$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 上下文中,这两个值是等效的("
字符在正则表达式中不需要转义,尽管转义它们也没有害处),但这是需要注意的事项。
- 恰巧在通过 PowerShell
-
避免引号和转义问题的简单方法是依赖于
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 asC:\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.
- 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: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
'...'
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"..."
overall; e.g., to makefold
contain verbatimValue=\"0\"
, useset "fold=Value=\"0\""
- As noted, the
~
in%~1
removes 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论