2010-08-10 54 views
8
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”的值,否?为什么“set -P”不能在管道之后工作?

如果有问题,我在Windows XP Pro,SP3上。

回答

11

管道似乎创建了一个新的CMD实例来执行下一个接收管道数据的命令。所以当管道结束时,CMD实例退出并且变量丢失。

+0

巧合的是,我需要从一个程序的stdout中取一个数字,对它进行一些数学计算,然后将它传递给另一个程序这似乎是诀窍: echo 5 |(set/P TmpVar = && set/a TmpVar/2)> C:\ test.txt – TonyM 2010-12-29 18:18:06

+1

+1;事实上,这个问题是由Windows如何实现管道造成的。请参阅[为什么在管道代码块内部延迟扩展失败](http://stackoverflow.com/q/8192318/1012053)以获取该机制的完整说明以及许多有趣的副作用。 – dbenham 2012-10-15 21:29:48

3

我不知道是什么DOCO 你已经看到set命令但set /?输出中明确规定:

/P开关允许将变量的值设置为用户输入的行号为

(my italics)。我认为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 

有上this page一个有趣的片断这表明它做背景:

好吧,我发现了为什么我自己。这是因为|创建了一个新的上下文,所以变量永远不会出现在当前上下文的其余部分。证明:
> set bar=

bar=aaa
> set bar
Environment variable bar not defined

虽然我拒绝对这一结论的真实性发表评论。我不知道这个意义上的上下文是什么,我只是为了完整性而提请你注意。

+0

对不起,我10多年来没有做过任何批处理编码,因此我的头被Unix的观念污染,STDIN是STDIN ...我想你是对的,“由用户”不是在默认情况下DOS环境中的“STDIN”的同义词(是的,我知道一些Unix程序拉动Wanky TTY检测的东西,但这是罕见的,很难实现异常:)我需要阅读更多关于这些上下文的内容(实际上昨晚看到了那个页面,但是太累了,不能完全解析它。 – DVK 2010-08-10 11:23:19

+1

嗯,我认为你确实是对的@DVK,尽管我在上面的答案中有我的原始段落。由于'set/p V1 = paxdiablo 2010-08-10 12:12:05

+1

该问题与SET命令无关,需要做的一切以及Windows如何实现管道,请参阅TonyM的回答,以及我在那里发表评论的链接 – dbenham 2012-10-15 21:32:07

1

这不是一个直接的答案,原来的问题,其中问Why doesn't [..] work?,但这个答案可以寻找到一个̲ç̲^h是有用的人̲我̲Ë̲ v ̲Ë̲会是什么逻辑结果的是这样的

echo:somevalue|set /p somevar= 

正常的解决方法,例如,用于上面的代码,将是:

echo:somevalue>tempfile.txt&set /p somevar=<tempfile.txt 

该做的工作完美,但它创建必须与事后处理(上的事实,我们需要采取额外的步骤,使顶新文件确定这个新的文件不会覆盖现有的我们没有创造或从未打算取代)。

虽然确实有周围使用一个文件流的桥梁横跨至于环境变量相关的管|操作两侧的空隙没有办法,在Windows NT环境下是和提供脚本驻留在使用NTFS文件系统的体积,可以使用的东西远比临时文件更优雅:alternate data streams

让我们直接进入一个例子说明一个可以如何使用它们:

echo:somevalue>".\%~nx0":temp&set /p somevar=<".\%~nx0":temp 

这里%~nx0代表,并得到扩大到中,我们的批处理文件,如果用引号括起来的(基本名称+扩展名),它包含空格。

注: 虽然人们可以使用%0直接(不带引号),而不是指 当前脚本,.\%~nx0更容易管理,如果你需要 看看指令的展开价值,同时调试你的脚本, 特别是如果你的脚本的完整路径是相当长的。

这样,".\%~nx0":temp备用数据流(ADS)我们命名temp自己脚本的,例如myscript.cmd:temp,我们创建(或覆盖)与echo命令的输出。由于ADS行为方式作为文件的默认流一样,echoset命令看不出任何区别。

使用该方法可能是这样一个完整的脚本:

@echo off 
set __self=".\%~nx0" 
set __adsname=test.dat 

:: Using some input... 
set [email protected],-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末,用于清除内容我们刚刚使用的备用数据流。虽然这种设置备用数据流的大小为零,但它确实不擦除它(见下面的注释)。

最后的一些注意事项:

  1. 大多数命令无法理解,或者当它们是作为源文件提供了备用数据流工作。这意味着不能使用以下几种:

    • 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命令。

  2. 虽然我们可以很容易地清楚/擦除的替代数据流的内容,删除一个是因为复制文件或重命名它不涉及任何流(以及:$DATA的)相当棘手,和编辑/改变文件内容只影响默认数据流。不过,我们必须根据我们正在努力实现哪几个选项:
    • 如果我们只有一个备用数据流不介意删除所有的人都一次,内容的文件只是文本,那么我们可以通过使用以下命令type myscript.cmd > myscript_clean.cmd保留只有原始文件的默认数据流来创建新文件,之后可以删除原始文件。
    • 如果我们有音量在Windows Vista或操作系统的更高版本运行的管理权限,我们可以使用MKLINK创建符号链接一个备用数据流,那么这将为我们提供一个标准文件名与通常的文件管理命令一起使用。
    • 或者,可以使用许多可用的工具之一来操纵备用数据流,如Streams,LADSAlternateStreamView
  3. 一个有用的命令列出常规文件包括从命令行备用数据流是dir /a-d /r。然后,您可以使用任何程序来访问文件的名称(备用)数据流,例如notepad.exe myscript.cmd:data

我希望这有助于!

相关问题