在Windows批处理文件中解析和传递特殊字符

4
我试图编写一个批处理文件,可以接受FTP链接的用户输入,解析出用户名、密码和域名,将它们写入文件,并将该文件作为FTP命令的输入调用。我已经成功地编写了这个程序,但是遇到了一个密码中包含!符号的情况。
FTP链接是系统自动生成的,可能包含特殊字符(例如:!^*)。
我正在使用setlocal delayedexpansion,因为我在for循环中使用/:@作为分隔符读取完整字符串(例如:ftp://userid:password@some.domain.com)。
我尝试了一些方法,如parse输出后执行endlocal delayedexpansion,但是标记不起作用,因为我结束了扩展操作。我还尝试过将每个标记写入其自己的文件,然后将文件内容分配为变量,但没有成功。
我认为应该有一种方法可以做到这一点,但我总是遇到困难。
以下是我的代码片段:
@ECHO OFF
setlocal enableextensions enabledelayedexpansion
echo Example FTP link:
echo.
echo "ftp://xxxxxxxx:yyyyyyyy@some.where.com"
echo.
set /p ftplink= Please enter full FTP link:  
echo.
set /p ftpfile= Please provide the file name you want to download:  

:FTPbat
:: Generate a bat file for FTP retrieval
for /f "tokens=1-4 delims=/:@" %%a in ("%ftplink%") do (
    set ftpdomain=%%~d
    set ftpuser=%%~b
    set ftppass=%%~c
    )

    echo open %ftpdomain%> get.ftp
    echo %ftpuser%>> get.ftp
    echo %ftppass%>> get.ftp
    echo binary>> get.ftp
    echo hash>> get.ftp
    echo mget %ftpfile%>> get.ftp
    echo disconnect>> get.ftp
    echo quit>> get.ftp 
:GetFTPFile
CLS
FTP -i -s:get.ftp

这是一个FTP链接的例子:

ftp://username:pas!word@somewhere.com

很不幸,特殊字符可以出现在密码字符串中的任何位置,甚至可能出现在用户名中。而且,用户名和密码的长度都不统一(即:每个都是8个字符)。我是通过艰难的方式才发现这一点的。
非常感谢任何形式的帮助。
2个回答

3

这很简单(如果你知道该怎么做)。 关键是只在禁用了延迟扩展模式的情况下扩展FOR参数(否则,延迟扩展阶段会修改“!”字符)。 但是为了使用变量内容,请始终使用延迟扩展模式(因为只有延迟扩展可以安全地扩展任何内容)。 因此,您需要切换模式。

参考:SO:Windows命令解释器(CMD.EXE)如何解析脚本?

SETLOCAL EnableDelayedExpansion    
(
  for /f "tokens=1-4 delims=/:@" %%a in ("!ftplink!") do (
    SETLOCAL DisableDelayedExpansion
    set "ftpdomain=%%~d"
    set "ftpuser=%%~b"
    set "ftppass=%%~c"

    SETLOCAL EnableDelayedExpansion    
    echo open !ftpdomain!
    echo !ftpuser!
    echo !ftppass!
    echo binary
    echo hash
    echo mget !ftpfile!
    echo disconnect
    echo quit
    ENDLOCAL
    ENDLOCAL
  )
) > get.ftp

这段代码是简化的,最好使用

...
(echo open !ftpdomain!)
(echo(!ftpuser!)
(echo(!ftppass!)
(echo binary)
...

括号可以避免尾随空格的问题。 在echo(后面加上丑陋的左括号是为了避免空变量或包含问题字符(如/?、ON´或OFF`)的变量出现问题。

这就是答案的本质。一旦你知道了它们,它们就变得微不足道了。在你知道之前,它们可能会让人恼火。感谢您提供解决方案、解释和链接。现在更多人都可以轻松掌握了。 :) - JChase

1
你当然可以完全不设置这些变量:
@Echo Off
Echo Example FTP link:
Echo(
Echo "ftp://username:password@domain.ext"
Echo(
Set /P "ftplink= Please enter full FTP link: "
Echo(
Set /P "ftpfile= Please provide the file name you want to download: "

(For /F "Tokens=2-4 delims=/:@" %%A In ("%ftplink%")Do (Echo open %%C
    Echo %%A
    Echo %%B
    Echo binary
    Echo hash
    Echo mget %ftpfile%
    Echo disconnect
    Echo quit))>get.ftp

ClS
FTP -i -s:get.ftp

你可以在需要时将这些变量保存以供脚本后续使用,只是你不需要在循环内部使用它们!
(For /F "Tokens=2-4 delims=/:@" %%A In ("%ftplink%")Do (Set "ftpuser=%%A"
    Set "ftppass=%%B"
    Set "ftpdomain=%%C"
    Echo open %%C
    Echo %%A
    Echo %%B
    Echo binary
    Echo hash
    Echo mget %ftpfile%
    Echo disconnect
    Echo quit))>get.ftp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接