返回列表 发帖
猜测句柄 4~9 的初始值不是有效句柄
做了一个测试试图证明当初始句柄不是有效句柄时,产生的备份句柄会保留,却得到了奇怪的结果:


A、测试中 3 和 4 为备份句柄:
3=1,4=2
而结束备份后句柄 4 仍无效
echo test >nul 2>nul
echo 无效句柄 1>&4 2>conCOPY
B、
测试中 3、4、5 为备份句柄:
3=1,4=2,5=3
结束备份后句柄 4 变成 3 所备份的状态
echo test >nul 2>nul 3>nul
echo 变成句柄3(nul) 1>&4 2>conCOPY
echo test >nul 2>nul 3>con
echo 变成句柄3(con) 1>&4 2>conCOPY
C、
测试中 3、4、5 为备份句柄:
3=1,4=2,5=3
结束备份后句柄 4 变成 nul
既不是 3 也不是 2,违背测试 C 体现的规律
echo test >nul 2>&1 3>&1
echo 变成 nul 1>&4 2>conCOPY
D、
这两个测试中 3、4、5 为备份句柄:
3=1,4=2,5=3
结束备份后句柄 4 变成 1 的原始状态
echo test >nul 3>nul 4>nul
echo 正确 1>&4 2>conCOPY
E、
这两个测试中 4、5 为备份句柄:
4=3,5=4
结束备份后句柄 4 仍是无效句柄
echo test 3>nul 4>nul
echo 错误 1>&4 2>conCOPY

TOP

有人能看出 16 楼测试结果的隐含规律吗?

TOP

本帖最后由 CrLf 于 2014-11-28 20:26 编辑

发现前面的说法有误,比较以下三个测试:
dir 4>&3COPY
dir >nul 4>&3COPY
dir 1>&3COPY
看来句柄 3~9 的初始状态都是无效句柄
是先发生备份(想过去这也是理所当然的),句柄 3 保存了句柄 1 的值,再执行了 1>&3,把句柄 3 的值借给句柄 1,命令执行完毕后,句柄 3 把备份还给句柄 1,所以看起来句柄 3 仿佛默认等于句柄 1 的初始状态

TOP

把以前的老帖翻出来炒冷饭
:: 句柄模拟.cmd - 模拟运算句柄操作后的句柄状态
:: qzwqzw - 2009-6-12
@echo off & setlocal EnableDelayedExpansion
if [%1]==[] (
    echo. 这是句柄操作示例, 模拟运算进行几次句柄操作后的句柄状态
    echo --------------------- call %~n0 ">nul" "2>nul" ---------------------
    call %0 ">nul" "2>nul"  
    set 句柄
    echo.
    echo --------------------- call %~n0 ">nul" "2>nul" "3>nul" ---------------------
    call %0 ">nul" "2>nul" "3>nul"  
    set 句柄
    echo.
    echo --------------------- call %~n0 ">nul" "2>&1" "3>&1" ---------------------
    call %0 ">nul" "2>&1" "3>&1"  
    set 句柄
    echo.
    echo --------------------- call %~n0 ">nul" "3>nul" "4>nul" ---------------------
    call %0 ">nul" "3>nul" "4>nul"  
    set 句柄
    echo.
    echo --------------------- call %~n0 "3>nul" "4>nul" ---------------------
    call %0 "3>nul" "4>nul"  
    set 句柄
    echo.
    pause
    goto :eof
)
set "0=con" & set "1=con" & set "2=con"
for %%h in (%句柄%) do set %%h
echo.----- 起始状态 Initiation state -----
for %%h in (0 1 2 3 4 5 6 7 8 9) do set/p=%%h=!%%h! <nul
echo.
echo.----- 预处理 Pre-process -----
:loop
if [%1]==[] goto :end
echo.----- %1 -------
set "_tmp=%~1"
if "%_tmp:~0,1%"=="<" set "_tmp=0%_tmp%"
if "%_tmp:~0,1%"==">" set "_tmp=1%_tmp%"
set _句柄=%_tmp:~0,1%
set _句柄_2=
set _dev=
if "%_tmp:~2,1%"=="&" (set _句柄_2=%_tmp:~3%) else (set _dev=%_tmp:~2%)
for %%h in (0 1 2 3 4 5 6 7 8 9) do (
    if "!%%h!"=="" (
        set/p=b: %_句柄%[!%_句柄%!]=^>%%h[!%%h!] : <nul
        set "%%h=!%_句柄%!"
        set bak_%%h=%_句柄%
        goto :set
    )
)
:set
for %%h in (0 1 2 3 4 5 6 7 8 9) do set/p=%%h=!%%h! <nul
echo.
if defined _dev (
    set/p=a: %_dev%=^>%_句柄%[!%_句柄%!] : <nul
    set %_句柄%=%_dev%
) else if defined _句柄_2 (
    set/p=a: %_句柄_2%[!%_句柄_2%!]=^>%_句柄%[!%_句柄%!] : <nul
    set %_句柄%=!%_句柄_2%!
)
for %%h in (0 1 2 3 4 5 6 7 8 9) do set/p=%%h=!%%h! <nul
echo.
shift
goto :loop
:end
echo.----- 后处理 Post-process -----
for %%h in (0 1 2 3 4 5 6 7 8 9) do (
    if not "!bak_%%h!"=="" (
        set/p=r: !bak_%%h![]^<=%%h[!%%h!] : <nul
        set !bak_%%h!=!%%h!
        set %%h=
        set bak_%%h=
        for %%h in (0 1 2 3 4 5 6 7 8 9) do set/p=%%h=!%%h! <nul
        echo.
    )
)
set 句柄=
for %%h in (0 1 2 3 4 5 6 7 8 9) do set 句柄=!句柄! "%%h=!%%h!"
endlocal & set 句柄=%句柄%
echo.----- 结束状态 End Status -----
for %%h in (%句柄%) do set/p=%%~h <nul
echo.COPY
1

评分人数

    • CrLf: 先加分再研究~技术 + 1
天的白色影子

TOP

回复 14# qzwqzw


    举那个例子可能有点不合适,因为(echo,|cls)>con与cls>con是一样的效果,但是下面这两句就不一样了。
(echo,|echo,)>conCOPY
echo,>conCOPY
但是若用句柄备份的思想来看待这个问题的话,那么可以再把这里的错位再还原回去:
(echo,|echo,)>con 1>&3COPY
它们表现出的现象何其相似,并且可以用这个方式来解释出现的原因并将之还原回去,所以我才说所谓的句柄备份是否背后的原因也是触发了你这里面提到的模式置换。

TOP

回复 20# amwfjhh
(echo,|echo,)>con 1>&3COPY
相同句柄的重定向只以最后一次为准,经过预处理,这里实际执行的重定向只有 1>&3,而句柄 3 是句柄 1 的备份,所以句柄 1 的重定向结果还是原来的句柄 1

TOP

回复 21# CrLf


    说的不错。我的理解是:
(cls|echo,)>conCOPY
当命令的执行结果被重定向到下一个非接收流的命令,并且过程被括起来重定向到con后,其实是相当于标准输出被重定向到了数据流,而数据流又被重定向到了con(这个非原始标准输出),则所有的输出内容都被看着流数据对待,特殊控制字符不再有其原始的控制效能,比如清屏,beep等,这个时候的输出内容就有点类似于debug的d命令右边显示字符的那块了,所有字节被看成普通文本对待,能显示就显示,不能显示留空跳过。当然它们的具体显示效果不同。

TOP

返回列表