我正在努力改进脚本,我建议将其作为How to write a batch file showing path to executable and version of Python handling Python scripts on Windows?问题的答案。要阻止打开对话框,我想读取ftype
命令的输出,提取路径
从中执行并检查它是否存在。
在此之后
@echo off
setlocal EnableDelayedExpansion
rem c:\ftype Python.File ->
rem Python.File="c:\path with spaces, (parentheses) and % signs\python.exe" "%1" %*
for /f "tokens=2 delims==" %%i in ('ftype Python.File') do (
set "reg_entry=%%i"
)
reg_entry's
内容
"c:\path with spaces and (parentheses) and % signs\python.exe" "%1" %*
如何拆分才能获得
"c:\path with spaces, (parentheses) and % signs\python.exe"
,"%1"
和%*
?
EDIT
我在阅读Aacini的答案后尝试使用call
,它几乎可以使用。但是,它不会处理%
符号。
@echo off
setlocal EnableDelayedExpansion
set input="c:\path with spaces and (parentheses) and %% signs\python.exe" "%%1" %%*
echo !input!
call :first_token output !input!
echo !output!
goto :eof
:first_token
set "%~1=%2"
goto :eof
输出
"c:\path with spaces and (parentheses) and % signs\python.exe" "%1" %*
"c:\path with spaces and (parentheses) and 1"
答案 0 :(得分:2)
这是Batch的直接功能。在批处理中,批处理文件的参数用空格分隔,参数可以用引号括起来,所以只需将reg_entry的值作为批处理文件的参数传递,其中包含每个参数:
C:\>type test.bat
@echo off
:loop
echo %1
shift
if not "%1" == "" goto loop
C:\>echo %reg_entry%
"c:\path with spaces and (parentheses) and % signs\python.exe" "%1" %*
C:\>test %reg_entry%
"c:\path with spaces and (parentheses) and % signs\python.exe"
"%1"
%*
答案 1 :(得分:2)
正如Aacini所说,使用CALL
语句可以通过内部参数拆分解决您的问题。
为了避免在%
之前丢失call
个符号,您可以在call
展开之前将其加倍。
keyline为set "input=!input:%%=%%%%!"
,其中一个解析器阶段的百分号为半,因此%
替换单%%
。
但即使这样,这个解决方案并不完美!
此解决方案在使用&<>|
这样的特殊字符时遇到问题,在您的情况下只有&
,因为这是文件名/路径中唯一的合法字符。
通过将行set "%~1=%2"
更改为set ^"%~1=%2"
可以避免这种情况,这可以确保%2使用周围的引号。
但现在你又遇到了另一个问题,所有的插入都加倍了
所以我必须用set "output=!output:^^=^!"
替换输出。
新代码看起来像这样
@echo off
setlocal EnableDelayedExpansion
set input="c:\path with spaces, exlcamation mark^!, ampersand &, carets ^ and (parentheses) and %% signs\python.exe" "%%1" %%*
echo !input!
set "input=!input:%%=%%%%!"
call :first_token output !input!
set "output=!output:^^=^!"
echo !output!
goto :eof
:first_token
set ^"%~1=%2"
goto :eof
编辑:用于处理感叹号!
您需要将:first_token
功能更改为
:first_token
setlocal DisableDelayedExpansion
set ^"temp=%2"
set ^"temp=%temp:!=^!%"
(
endlocal
set ^"%~1=%temp%"
)
goto :eof
答案 2 :(得分:2)
与CALL解析器非常相似的替代解析器是简单的FOR。有两个复杂因素:
1-如果在包含!
的情况下启用延迟扩展,则不得展开FOR。这很容易处理。
2-内容不得包含通配符*
或?
。 ?
可以暂时替换,然后返回。但是没有简单的方法来搜索和替换*
。
由于此问题试图解析路径,并且路径不能包含通配符,因此无需使用CALL即可轻松解决此问题。为了完整性,我在测试用例中添加了!
。
@echo off
setlocal disableDelayedExpansion
set input="c:\path with spaces, ampersand &, carets ^ and (parentheses)! and %% signs\python.exe" "%%1" %%*
set input
set "output="
setlocal enableDelayedExpansion
for %%A in (!input!) do if not defined output endlocal & set output=%%A
set output
如果我们可以依赖第一个令牌将始终用引号括起来的事实,那么解决方案就更容易了。我们可以使用FOR / F,EOL和DELIMS都设置为"
。
@echo off
setlocal disableDelayedExpansion
set input="c:\path with spaces, ampersand &, carets ^ and (parentheses)! and %% signs\python.exe" "%%1" %%*
set input
set "output="
setlocal enableDelayedExpansion
for /f eol^=^"^ delims^=^" %%A in ("!input!") do endlocal & set output="%%A"
set output
但是,我只看了我的FTYPE输出,发现一些条目没有被引用,即使它们在路径中包含空格!我不认为此页面上的任何答案都可以解决这个问题。事实上,问题背后的整个前提可能存在缺陷。
答案 3 :(得分:1)
基本上你要做的就是将整个字符串转换为它的元素,就像解析器一样。在你的情况下,由于Windows规则允许空格被允许,词汇分析可能会成功。
从根本上说,您需要在.cmd文件中使用标签和条件格式构建有限状态机。 FSA拥有处理您希望收集的元素的各个部分的州。在开始状态中,您决定是否看到空白(跳过并返回开始),双引号(转到处理双引号字符串的FSA部分),或者是非空白的部分(转到部分)收集非空白字符的FSA。)
收集双引号字符串的FSA部分选择字符,直到找到另一个双引号;这就是让你在双引号字符串中捕获空格的原因。我想你必须检查一个“转义”双引号(连续两个),如果找到,用一个双引号替换它们并继续收集字符。
这非常难看,因为CMD脚本具有非常糟糕的字符串处理功能。通过在DOS命令提示符下键入HELP SET
,可以找到您需要知道的每个(丑陋)事物。特别是,子字符串格式为%VAR:~n,m%
,从环境变量m
中的索引n
开始挑选%VAR%
个字符。我发现它对SET TEMP=%VAR%
很有用,然后通过简单的序列逐一从%TEMP%
剥离字符,例如
SET CHAR=%TEMP:~0,1%
SET TEMP=%TEMP:~1%
享受。