C:\>type c:\output.txt
abcd
C:\>type c:\output.txt | set /p V1=
C:\>set
... A bunch of junk, NOT seeing "V1"
发生了什么?根据我看过的所有SET
文档,%V1%应该从上面被分配一个值为"abcd",是吗?
如果有影响的话,我在Windows XP Pro SP3上。
C:\>type c:\output.txt
abcd
C:\>type c:\output.txt | set /p V1=
C:\>set
... A bunch of junk, NOT seeing "V1"
发生了什么?根据我看过的所有SET
文档,%V1%应该从上面被分配一个值为"abcd",是吗?
如果有影响的话,我在Windows XP Pro SP3上。
管道似乎会创建一个新的CMD实例来执行接收管道数据的下一条命令。因此,当管道结束时,该CMD实例退出并且变量将被丢失。
set /?
的输出清楚地说明:
/P开关允许你将变量的值设置为由用户输入的一行输入。
(我加了斜体)。我认为set /p
无论你尝试通过标准输入管道传入什么内容,它都会从控制台获取输入。我不确定为什么它没有等待。 echo xxx | set /p xx=
也无法设置变量。
但是,如果你想从单行文件中设置一个变量,你可以使用以下任意一种方法:
for /f "delims=" %%i in (c:\output.txt) do set V1=%%i
set /p V1=<c:\output.txt
第二种方法是最简单的,但如果你想获取任意命令的输出,它并没有太大帮助,但你可能需要先将其重定向到文件中。
第一种方法允许你执行任意命令,而无需使用临时文件:
for /f "delims=" %%i in ('echo AAA') do set xx=%%i
|
创建了一个新的上下文,所以变量永远不会到达当前上下文的其余部分。证明:> set bar=
> echo aaa | (set /p bar= && set bar)
bar=aaa
> set bar
环境变量bar未定义
set /p V1=<c:\output.txt
可以正常工作。只是管道类型似乎不起作用。 - paxdiabloecho:somevalue|set /p somevar=
echo:somevalue>tempfile.txt&set /p somevar=<tempfile.txt
它的功能非常完美,但是它会创建一个新文件,必须在之后处理(除了我们需要采取额外步骤来确保这个新文件不覆盖我们没有创建或从未打算替换的现有文件)。
虽然对于环境变量而言,在使用管道符 |
操作符跨越两侧之间,确实绕不过使用文件流,只要处于 Windows NT 环境下,并且提供的脚本所在的卷正在使用 NTFS 文件系统,则可以使用比临时文件更优雅的东西:备用数据流
让我们直接进入一个示例,说明如何使用它们:
echo:somevalue>".\%~nx0":temp&set /p somevar=<".\%~nx0":temp
这里的%~nx0
代表并会被扩展为我们批处理文件的文件名(包括基本名称和扩展名),如果文件名中包含空格,则用引号括起来。
注意:虽然可以直接使用
%0
(不带引号)来引用当前脚本,但如果您需要在调试脚本时查看命令的扩展值,特别是如果您的脚本的完整路径非常长,则.\%~nx0
更易于管理。
因此,".\%~nx0":temp
指的是我们自己脚本的一个名为temp
的备用数据流(ADS),例如myscript.cmd:temp
,我们使用echo
命令的输出来创建(或覆盖)它。由于ADS的行为与文件的默认流相同,因此echo
和set
命令没有任何区别。
一个完整的使用该方法的脚本可能如下所示:
@echo off
set __self=".\%~nx0"
set __adsname=test.dat
:: Using some input...
set l_input=@FirewallAPI.dll,-23000
echo:Input: %l_input%
echo:
:: ...we process it...
expand_str_res_id.exe %l_input%>%__self%:%__adsname%&set /p l_output=< %__self%:%__adsname%
:: ...and show the output, e.g. "File and Printer Sharing"
echo:Output: %l_output%
echo:
:cleanup
set l_input=
set l_output=
type nul> %__self%:%__adsname%
set __self=
set __adsname=
pause
type nul>%__self%:%__adsname
,它可以扩展为类似于type nul>“.\myscript.cmd”:test.dat
的内容,用于清除我们刚才使用的备用数据流的内容。尽管这将备用数据流的大小设置为零,但它并没有抹掉它(请参见下面的注释)。大多数命令不能理解或处理备用数据流,当它们被提供为源文件时。这意味着以下命令不能使用:
type
,例如:type myscript.cmd:data > myscript_data.txt
copy
,例如:copy myscript.cmd:data myscript_data.txt
move
,例如:move myscript.cmd:data myscript_data.txt
del
/erase
,例如:del myscript.cmd:data
ren
/rename
,例如:ren myscript.cmd:data myscript.cmd:data.txt
实际上,只有文件重定向支持备用数据流,有一个例外(我所知道的): start
命令。
:$DATA
),而编辑/更改文件的内容只会影响默认数据流。尽管如此,根据我们想要实现的目标,我们仍有一些选择:
type myscript.cmd > myscript_clean.cmd
,然后可以删除原始文件。dir /a-d /r
。然后可以使用任何程序访问文件的名称(备用)数据流,例如:notepad.exe myscript.cmd:data