为什么不“set -P”管道后工作?
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"
What happened? According to all documentation for SET
I've seen, %V1% should have been assigned a value of "abcd" from the above, no?
I'm on Windows XP Pro, SP3 if it matters.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不知道您在
set
命令中看到了什么,但set /?
的输出清楚地表明:(斜体)。我认为 set /p 正在从控制台获取输入,无论您尝试通过标准输入输入什么内容。为什么不等待,我不确定。回声xxx | set /p xx= 也无法设置变量。
但是,如果您想从单行文件设置变量,则可以使用其中之一:
第二个是最简单的,但如果您想获取任意命令的输出,则它没有多大帮助,但您可以我们必须首先将其定向到一个文件。
第一个允许您在没有临时文件的情况下执行任意命令:
尽管我拒绝评论该结论的准确性。我不知道这个意义上的上下文是什么,我只是为了完整性而提请您注意。
I don't know what doco you've seen for the
set
command but the output ofset /?
clearly states:(my italics). I think
set /p
is getting its input from the console regardless of what you're trying to pipe in through standard input. Why it's not waiting, I'm not sure.echo xxx | set /p xx=
also fails to set the variable.But, if you want to set a variable from a single line file, you can just use one of these:
That second one is the simplest but it doesn't help much if you want to grab the output of an arbitrary command but you may well have to direct it to a file first.
The first one allows you to execute arbitrary commands without temporary files:
There's an interesting snippet on this page which suggests it has to do with contexts:
although I decline to comment on the veracity of that conclusion. I don't know what contexts are in this sense, I'm just bringing it to your attention for completeness.
这不是对原始问题的直接答案,该问题问
为什么 [..] 不起作用?
,但这个答案对于那些寻找 a̲c̲h̲i̲e̲v̲e̲ 逻辑的人来说可能很有用。类似这样的结果:正常的解决方法,例如上面的代码,将是:
它完美地完成了工作,除了它创建了一个必须在之后处理的新文件(事实上我们需要采取额外的步骤来确保这个新文件不会覆盖我们未创建或从未打算替换的现有文件)。
虽然确实如此,但就环境变量而言,没有办法使用文件流来桥接管道
|
运算符两侧的间隙,因为在Windows NT 环境,并且假设脚本所在的卷使用 NTFS 文件系统,可以使用比临时文件更优雅的东西:备用数据流让我们直接跳到一个示例来说明如何使用它们:
这里
%~ nx0
代表并扩展为批处理文件的文件名(基本名称+扩展名),如果包含空格,则用引号引起来。因此,
".\%~nx0":temp
指的是我们自己名为的脚本的备用数据流 (ADS) temp
,例如myscript.cmd:temp
,我们使用echo
命令的输出创建(或覆盖)。由于 ADS 的行为方式与文件的默认流相同,因此echo
和set
命令看不出任何差异。使用该方法的完整脚本可能如下所示:
这里,在脚本末尾,行
type nul>; %__self%:%__adsname
,可以扩展为类似type nul>; ".\myscript.cmd":test.dat
,用于清除我们刚才使用的备用数据流的内容。尽管这将备用数据流的大小设置为零,但它不会删除它(请参阅下面的注释)。最后一些注意事项:
当备用数据流作为源文件提供时,大多数命令无法理解或使用它们。这意味着不能使用以下内容:
类型
,例如类型 myscript.cmd:data > myscript_data.txt
复制
,例如复制myscript.cmd:data myscript_data.txt
移动
,例如move myscript.cmd:data myscript_data.txt
del
/擦除
,例如del myscript.cmd:data
ren
/重命名
,例如ren myscript.cmd:data myscript.cmd:data.txt
事实上,它实际上只是支持备用数据流的文件重定向有一个例外(我能想到的):
start
命令。:$ DATA those),编辑/更改文件内容仅影响默认数据流。不过,根据我们想要实现的目标,我们有一些选择:- 如果我们只有一个备用数据流或不介意一次删除所有它们,并且文件的内容只是文本,那么我们可以使用以下命令
- 如果我们对卷拥有管理权限并且在 Windows Vista 或更高版本的操作系统下运行,我们可以使用 MKLINK 创建到一个备用数据流的符号链接,然后该数据流将为我们提供与常用文件管理命令一起使用的标准文件名.
- 或者,可以使用众多可用工具之一来操作备用数据流,例如 流、LADS 或 AlternateStreamView。
type myscript.cmd > 通过仅保留原始文件的默认数据流来创建新文件myscript_clean.cmd
,之后即可删除原文件。dir /ad /r
。然后,您可以使用任何程序访问文件的名称(备用)数据流,例如notepad.exe myscript.cmd:data
我希望这会有所帮助!
This is not a direct answer to the original question, which asked
Why doesn't [..] work?
, but this answer can be useful to people looking to a̲c̲h̲i̲e̲v̲e̲ what would be the logical result of something like this:The normal workaround, for example for the code above, would be:
which does the work perfectly, except that it creates a new file which has to be dealt with afterwards (on top of the fact that we need to take extra steps to make sure this new file doesn't overwrite an existing one we didn't create or never intended to replace).
While it is true there is no way around using a file stream to bridge the gap across both sides of the pipe
|
operator as far as environment variables are concerned, being under a Windows NT environment, and provided the volume the script resides on is using the NTFS filesystem, one can use something far more elegant than temporary files: alternate data streamsLet's jump right into an example illustrating how one might use them:
Here
%~nx0
stands for, and gets expanded to, the filename (base name + extension) of our batch file, enclosed in quotes in case it contains spaces.As such,
".\%~nx0":temp
refers to an alternate data stream (ADS) of our own script namedtemp
, for examplemyscript.cmd:temp
, that we create (or overwrite) with the output of theecho
command. Since ADS behave the same way as the default stream of a file, theecho
andset
commands don't see any difference.A complete script using the method could look like this:
Here, at the end of the script, the line
type nul> %__self%:%__adsname
, which could be expanded to something liketype nul> ".\myscript.cmd":test.dat
, is used to clear the content of the alternate data stream we just used. Although this sets the size of the alternate data stream to zero, it does not erase it (see notes below).Some final notes:
Most commands cannot understand or work with alternate data streams when they are provided as source files. This means the following ones cannot be used:
type
, e.g.type myscript.cmd:data > myscript_data.txt
copy
, e.g.copy myscript.cmd:data myscript_data.txt
move
, e.g.move myscript.cmd:data myscript_data.txt
del
/erase
, e.g.del myscript.cmd:data
ren
/rename
, e.g.ren myscript.cmd:data myscript.cmd:data.txt
In fact, it's really only file redirection that supports alternate data streams with one exception (that I can think of): the
start
command.:$DATA
ones), and editing/changing the content of a file only affects the default data stream. Still, we have a few options depending on what we're trying to achieve:type myscript.cmd > myscript_clean.cmd
, after which the original file can be deleted.dir /a-d /r
. You can then use any program to access the names (alternate) data stream of a file, e.g.notepad.exe myscript.cmd:data
I hope this helps!
要添加一个如何确认其他答案的简短示例,您可以使用另一个设置命令 IE 立即检查管道另一侧的变量内容:
ECHO HELLO | (set /P hi= && set hi)
将输出
hi=HELLO
但执行后变量被破坏:(,因此进一步的 'set hi' 将显示:
环境变量 hi 未定义
To add a brief example of how to confirm the other answers, you can immediately check the contents of the variable on the other side of the pipe using another set command IE:
ECHO HELLO | (set /P hi= && set hi)
Will output
hi=HELLO
But after execution the variables are destroyed : (, so a further 'set hi' will reveal:
Environment variable hi not defined
管道似乎创建了一个新的 CMD 实例来执行接收管道数据的下一个命令。因此,当管道结束时,该 CMD 实例将退出并且变量将丢失。
The pipe seems to create a new CMD instance to carry out the next command that is receiving the pipe data. So when the pipe has concluded, that CMD instance exits and the variable is lost.