批处理之家's Archiver

CrLf 发表于 2011-7-18 00:44

[分享]批处理利用set /p与重定向输入分行获取文本内容

[i=s] 本帖最后由 CrLf 于 2012-1-31 13:22 编辑 [/i]

起因是前几天的某个帖子中看到 cmd<1.txt 的用法,原以为1.txt 中的 pause 之所以被跳过是因为执行完后马上接收到了一个回车符,于是我把1.txt 中的所有 pause 都改成 pause&rem ,并去除所有回车符进行试验,下为去除回车符的代码:[code]@echo off&setlocal enabledelayedexpansion
set hh=^


::获取换行符
for %%a in (
        "@echo off" "pause&rem" "echo abc" "pause&rem"
) do set str=!str!!hh!%%~a
echo !str:~2!>3.txt
::只用换行符断行

cmd<3.txt
echo;
echo ________end________
pause[/code]假设修改后 1.txt内容如下(测试时,此文本中不存在回车符):[code]@echo off
pause&rem
echo abc
pause&rem[/code]结果仍然没有等待用户输入,并且还吞掉了下一行 echo 的第一个字符,导致 cmd 显示:[code]
        请按任意键继续. . .
        'cho' 不是内部或外部命令,也不是可运行的程序
        或批处理文件。
        请按任意键继续. . .[/code]对此感到非常疑惑,百思不得其解之下去请教寒夜版主,他问我 pause 等待的是什么输入,我才忽然醒悟,原来 pause 等待的是“任意键”,也就是说,它把 echo 的 e 当作用户输入给接收了(因为行末的 0D 0A被 cmd 接收了,所以 pause 接收的第一个字符就是下一行的首字符 e),因此这里用 pause 无法实现暂停的效果,这就推翻了我原来的认识,证明等待用户输入的命令并不是以回车符作为终止输入的信号。
(另:其实现想来这个问题也好解决,既然是类似 cmd /c "pause"<1.txt 这样的原因造成 pause 从 1.txt 获取了任意输入,那么改成 pause<con 即可重定向为从键盘获取输入)

进一步思考一下,众所周知, set /p 首行=<1.txt 能获取 1.txt 第一行,那么对含有大量 set /p 的语块进行重定向,又是什么结果呢?[code]@echo off
(for /l %%a in (1 1 10) do set /p .%%a=)<%0
set.
pause
[/code]可以看到,通过 set /p 配合重定向,能够把文本每一行都设为变量值,这是全新的技巧,更重要的是,这是一种全新的遍历文本的方式,它相当于不跳过空行的 for until ,这与 for /f 的 skip 参数相映成趣,而且还对特殊字符有极佳的兼容性。不过有得必有失,使用 set /p 赋值时,变量长度不能超过 1024 字节,所以局限了这个技巧的适用范围。
        
激动之余,又产生了两个疑惑:
    1、set /p 是以什么为依据断行
    2、当循环数大于文本行数时,为什么没有停顿下来等待用户输入

和寒夜版主一起做了几个试验,证明无论是单纯的 0D 回车符或者 0A 换行符都无法实现平时在 cmd 窗口中敲回车结束 set /p 输入的效果,必须出现连续的一组 0D 0A 才能够终止对一个 set /p 的输入。关于终止 set /p 输入的“特征码”,25 楼的 mxxcgzxxx 提出了更合理的猜想:0D 0A 和 0A 0D 这两种组合都能起到终止 set /p 输入的作用。
(25楼链接:[url=http://bbs.bathome.net/viewthread.php?tid=13327&page=2&fromuid=30406#pid86638]http://bbs.bathome.net/viewthrea ... muid=30406#pid86638[/url])
        
而第二个问题,绕了半天弯子终于得到一个比较合理的猜测:当重定向的输入被前面执行的命令取用完的时候,剩下的就是从空设备的输入,也就是 set /p .5=<nul。所以假如文本有N行,那么超过第 N 次的 set /p 都接收到了来自空设备的输入因而没有被赋值,示例如下,假设原 bat 为:[code](set /p .a=
set /p .b=)<只有一行的文件.txt
set.[/code]其作用相当于:[code]set /p .a=<只有一行的文件.txt
::取首行
set /p .b=<nul
::从空设备获取输入,等于无输入
set.
::显示以 . 开头的变量[/code]通过这个猜测和其他一些命令接收重定向输入时表现出的特性衍生出一个推测,那就是 cmd 在接受重定向输入到命令的时候,也许是一个字符一个字符顺序传递给语块\语句的,那些能够接受重定向输入的命令会自发地从中获取输入,直到命令自行关闭输入句柄为止。
        
这可以理解为 cmd 中出现重定向输入的时候,输入中的字符在排队等候被命令依次提走,一直到无字符可提的时候,重定向输入的来源就成为了一个空设备 nul。
        
好比一个旅行团在打车,出现愿意载客的出租车时,队伍就有序地依次上车,一辆车客满后就再等下一辆(旅行团并不知道当前这辆车何时客满,他们只需要机械地让排头的人上车、直到司机喊停为止),最终所有人都打车走光,这时候新来的出租车就找不到客人了,所以空车离开时当然还是空车。
        
当然有些命令是以任意合法字符或者固定字符来判定何时结束输入的,比如 choice、set /p 和 pause,这就很有利用的价值。
        
此处仅以 set /p 举几个例子:[code]@echo off
set /p line=要获取的行所在行数:
(for /l %%a in (1 1 %line%) do set /p 内容=)<a.txt
set 内容
::获取指定行内容的新方法,由于无需遍历整个文本,要获取的行位置靠前的情况下有很大优势[/code][code]@echo off
(for /l %%a in (1 1 100) do set /p .%%a=)<%0

::不跳过空行赋值,但是 tmplinshi 版主的测试结果表明这比常规办法稍慢,它只在某些场合有优势,比如只获取前 N 行时,或者要兼容空行的情况,再或者需要兼容特殊字符的时候。[/code](5楼链接:[url=http://bbs.bathome.net/viewthread.php?tid=13327&page=1&fromuid=30406#pid86516]http://bbs.bathome.net/viewthrea ... muid=30406#pid86516[/url])[code]@echo off&setlocal enabledelayedexpansion

set n=1
(for /l %%a in (1 1 5) do (
    if defined .!n! set /a n+=1
    set /p .!n!=
))<%0
::当然也同样可以跳过空行只将前 N 行赋值,但是这里的“前 N 行”计数时其实还是包括空行的,如果是要求取不把空行计算在内的前 N 行,我想最经济的方法就是先用 findstr . a.txt 输出非空行再分别赋值了[/code][code]@echo off
(for /l %%a in (1 1 7) do (
    pause
    set /p echo=
    echo !echo!
)<%0
::去除每行行首第一个任意字符的另一种方法,如果不计较效率的话,用 choice 可以只保留指定字符[/code][code]@echo off
(for /l %%a in (1 2 7) do (
    set /a a=1,b=2
    set /p a=
    set /p b=
    if !a!==!b! echo 相等
)<%0
::以两行为周期判断其内容是否相等,这比起老方法省下了许多麻烦,比如无需用 setlocal、endlocal 来兼容特殊字符[/code][code]@echo off
(for %%a in (
1-关回显 2-循环体 3-循环内容 4-do 4-设变量 5-输入 6-查看变量 7-注释
) do (
    set /p .%%a=
))<%0
set.
::可以通过无参数的for来循环,实现了以往无法实现的效果[/code][code]@echo off&setlocal enabledelayedexpansion
(for /f "tokens=1* delims=:" %%a in ('findstr /n .* 1.txt') do (
    set t2=
    set /p t2=
    echo;%%b!t2!
))<2.txt>合并.txt
::由于可以有两个不同的输入来源并存,所以双文本乃至多文本合并就成为轻而易举的事了[/code][code]@echo off&setlocal enabledelayedexpansion
for %%a in (a\*.txt b\*.txt) do set /a n+=1
dir /b /a-d /o-n b\*.txt>list.$
::计算文件总数为 %n%,生成要复制的文件列表为 list.$
(for /l %%a in (1 1 %n%) do (
        if not exist a\%%a.txt (
                set /p f=
                copy "b\!f!" "a\%%a.txt"
        )
))<list.$
::以往让人头疼的按递增文件名复制文件的问题,也可以这样解决
del /f list.$>nul
pause[/code]无奈的是,可以分段接受重定向输入的命令寥寥无几,所以暂时还没有想到更多的实用技巧,还是等待大家来补充吧。

[size=5][color=black][b]感谢 寒夜孤星、mxxcgzxxx、tmplinshi 等人的指点和共同探讨、测试。[/b][/color][/size]

mxxcgzxxx 发表于 2011-7-18 07:43

由于楼主的研究精神,于是乎截取文本头几行,或截取文本指定行的问题迎刃而解!
赞一个

tmplinshi 发表于 2011-7-18 09:52

不错,有一定的实用性。

例如,再也不用使用 findstr 来保留空行了,只不过要知道文本的行数。示例:[code]@echo off
set str=
(
    for /l %%a in (1 1 7) do (
        setlocal enabledelayedexpansion
        set /p str=
        if defined str (echo !str!) else echo ---------空行
        endlocal
    )
) <a.txt
pause[/code]

CrLf 发表于 2011-7-18 10:05

获取文件行数可以用:[code]find /c /v ""<1.txt[/code]虽然也是外部命令,但是效率比 findstr /n 要高

tmplinshi 发表于 2011-7-18 10:22

[i=s] 本帖最后由 tmplinshi 于 2011-7-18 11:35 编辑 [/i]

我测试了一个 11651 行的文本(没有空行),结果是 for /f 更快。

[color=Blue]测试代码:[/color]

set_p.bat:[code]@echo off
(
    for /l %%a in (1 1 11651) do (
        setlocal enabledelayedexpansion
        set /p str=
        echo,!str: =_!
        endlocal
    )
) <test.txt >test_1.txt[/code]for_f.bat:[code]@echo off
(
    for /f "delims=" %%a in (test.txt) do (
        set str=%%a
        setlocal enabledelayedexpansion
        echo,!str: =_!
        endlocal
    )
) >test_2.txt[/code][color=Blue]测试结果:[/color]
[quote]e:\我的文档\桌面>timeit set_p.bat

Version Number:   Windows NT 5.1 (Build 2600)
Exit Time:        10:19 am, Monday, July 18 2011
Elapsed Time:     0:00:15.500
Process Time:     0:00:14.031
System Calls:     430474
Context Switches: 56632
Page Faults:      39304
Bytes Read:       19381026
Bytes Written:    741100
Bytes Other:      2573192

e:\我的文档\桌面>timeit for_f.bat

Version Number:   Windows NT 5.1 (Build 2600)
Exit Time:        10:20 am, Monday, July 18 2011
Elapsed Time:     0:00:12.484
Process Time:     0:00:12.328
System Calls:     159911
Context Switches: 2458
Page Faults:      15433
Bytes Read:       598486
Bytes Written:    597572
Bytes Other:      2345164[/quote]

tmplinshi 发表于 2011-7-18 10:36

[code]@echo off
setlocal enabledelayedexpansion
(
    for /l %%a in (1 1 7) do (
        pause >nul
        set /p echo=
        echo !echo!
    )
) <%0
pause[/code]有点想不通的是,pause 为什么不直接接收 %0 的内容,而要接收它下一行的 set /p。

cjiabing 发表于 2011-7-18 10:45

很好很强大,值得研究

mxxcgzxxx 发表于 2011-7-18 10:54

[i=s] 本帖最后由 mxxcgzxxx 于 2011-7-20 22:36 编辑 [/i]

[quote]@echo off
setlocal enabledelayedexpansion
(
    for /l %%a in (1 1 10) do (
        pause >nul
        set /p echo=
        echo !echo!
    )
)
[size=2][color=#999999]tmplinshi 发表于 2011-7-18 10:36[/color] [url=http://www.bathome.net/redirect.php?goto=findpost&pid=86518&ptid=13327][img]http://www.bathome.net/images/common/back.gif[/img][/url][/size][/quote]

有趣的结果:起头的()被忽略,最后一个P被上一行吃了
所以用这种办法还得小心

tmplinshi 发表于 2011-7-18 11:00

[b] [url=http://bathome.net/redirect.php?goto=findpost&pid=86524&ptid=13327]8#[/url] [i]mxxcgzxxx[/i] [/b]


是每一行前面的第一个字符没有了,顶楼有说。

mxxcgzxxx 发表于 2011-7-18 11:05

[i=s] 本帖最后由 mxxcgzxxx 于 2011-7-18 11:11 编辑 [/i]

[b] [url=http://www.bathome.net/redirect.php?goto=findpost&pid=86526&ptid=13327]9#[/url] [i]tmplinshi[/i] [/b]
哦,是啊,没注意,pause吃了后面的输入!
也就是说<%0被分成了两下,第一个字被pause吃了,剩下的才轮到set/p,
可以用作去头几个字符用了[code]@echo off
setlocal enabledelayedexpansion
::从每行第三个字符截取
(
    for /l %%a in (1 1 10) do (
        for /l %%1 in (1 1 3) do pause >nul
        set /p echo=
        echo %%a !echo!
        )
) <%0
pause[/code]

CrLf 发表于 2011-7-18 11:12

[b] [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=86518&ptid=13327]6#[/url] [i]tmplinshi[/i] [/b]

5楼结果是因为 for 会跳过空行,如果要兼容空行的话,结果就要反过来了...
pause 是有接收字符的,它接收“任意字符”,也就是把每行开头的那个字符给吞了

mxxcgzxxx 发表于 2011-7-18 11:50

下面这个测试很有趣。空行被吃一个字符后,理应是换行符被吃,但造成换行符加下一行的(被吸上来了[code]@echo off
setlocal enabledelayedexpansion

(
    for /l %%a in (1 1 10) do (
        pause>nul
        set /p echo%%a=
        echo %%a !echo%%a!
        )
) <%0
pause[/code]

tmplinshi 发表于 2011-7-18 12:07

[b] [url=http://bathome.net/redirect.php?goto=findpost&pid=86534&ptid=13327]12#[/url] [i]mxxcgzxxx[/i] [/b]


截图工具推荐用 FSCapture:
    颜色少的用 png 格式,保存时选 256 色;
    颜色多的用 jpg 格式,比如人物照片等。

Batcher 发表于 2011-7-18 13:24

[b] [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=86537&ptid=13327]13#[/url] [i]tmplinshi[/i] [/b]


Reduce Color, 2 Colors
这样是不是更小更清晰

mxxcgzxxx 发表于 2011-7-18 13:27

[i=s] 本帖最后由 mxxcgzxxx 于 2011-7-18 13:40 编辑 [/i]

[b] [url=http://www.bathome.net/redirect.php?goto=findpost&pid=86537&ptid=13327]13#[/url] [i]tmplinshi[/i] [/b]

学习,之前没想过这个问题哈,是要省点空间
我都是用抓屏键,用图画工具弄的,换成PNG反面有50多KB

CrLf 发表于 2011-7-19 01:00

[b] [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=86516&ptid=13327]5#[/url] [i]tmplinshi[/i] [/b]


我用2235行的厚黑学全集试了试(题外话,下载回来都木油看过,原来这玩意就是用来测试的...),结果相差无几
for /f:[code]@echo off
echo %time%
(
    for /f "delims=" %%a in (test.txt) do (
        set str=%%a
        setlocal enabledelayedexpansion
        echo,!str: =_!
        endlocal
    )
) >test_2.txt
echo %time%
pause[/code]回显:[code] 0:55:30.77
0:55:32.83
请按任意键继续. . .[/code]set /p:[code]@echo off
echo %time%
(
    for /l %%a in (1 1 2235) do (
        setlocal enabledelayedexpansion
        set /p str=
        echo,!str: =_!
        endlocal
    )
) <test.txt >test_1.txt
echo %time%
pause[/code]回显:[code] 0:55:34.07
0:55:36.37
请按任意键继续. . .[/code]结果是 2.04:2.30,差距约为十分之一...视实际情况而定吧,毕竟遍历方式以及来源的异同决定了这两种用法有各自适用范围~

batman 发表于 2011-7-19 08:33

很好,很强大!!!
庆贺又一bathome原创技术的诞生!!!

mxxcgzxxx 发表于 2011-7-19 08:41

[i=s] 本帖最后由 mxxcgzxxx 于 2011-7-19 08:45 编辑 [/i]

从特殊字符方面来说还是有很大区别的[code]!@#~#$%^&*()_+-={}|":?><;'\`"~!@#$%^&*()_+|":?><[/code]用SET/P和FOR/F分别读取并输出[code]@echo off
setlocal enabledelayedexpansion
(
    for /l %%a in (1 1 1) do (
        set/p echo=
        echo.!echo!
        )
) <1.txt >2.txt

for /f "delims=" %%1 in (1.txt) do (
       set "str=%%1"
       echo !str!
       )>>2.txt[/code]结果[code]!@#~#$%^&*()_+-={}|":?><;'\`"~!@#$%^&*()_+|":?><
?><;'\`"~?><[/code]说明,如果在有特殊字符的情况下,SET/P更加合理而简便

mxxcgzxxx 发表于 2011-7-19 09:18

[i=s] 本帖最后由 mxxcgzxxx 于 2011-7-19 09:39 编辑 [/i]

[code]@echo off
setlocal enabledelayedexpansion
(
       set/p a=
       set/p b=
       set/p c=
       echo.!a!
       echo.!b!
       echo.!c!
       )<1.txt >2.txt
[/code]这样子是一次性获取头三行信息,
利用这个可进行隔行获取[code]@echo off
(
     for /l %%1 in (1 1 10 ) do (
       setlocal enabledelayedexpansion
       set/p 偶数行=
       set/p 奇数行=
       echo.!偶数行!>>2.txt
       echo.!奇数行!>>3.txt
       endlocal
       )
)<1.txt [/code]测试了多种组全发现,SET/P可以全文吸收一个字符都不错,
但无法跳过空行是一个优点也是一大问题

CrLf 发表于 2011-7-19 09:44

[i=s] 本帖最后由 zm900612 于 2011-7-19 09:53 编辑 [/i]

[b] [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=86589&ptid=13327]18#[/url] [i]mxxcgzxxx[/i] [/b]

可以用开闭变量延迟来提升对特殊字符的兼容性,但是我没测试过这个动作对效率的影响:[code]@echo off
for /f "delims=" %%1 in (1.txt) do (
       endlocal
       rem 此时关闭变量延迟以免 %%1 中含有 ! 致错
       set "str=%%1"
       setlocal enabledelayedexpansion
       rem 此时打开变量延迟以即时读取变量
       echo !str!
)>>2.txt[/code]另外,要跳过的行可以不赋值...三行一周期,获取周期中的首尾两行:[code](@echo off

for /l %%a in (1 1 12) do (
    set .1=
    set .2=
    set /p .1=
    set /p=
    set /p .3=
    echo;!.1!
    echo;!.2!
))<%0
pause[/code]确实,不跳过空行既是优点也是缺点,另外还有两个不知道是优点还是缺陷的特性,一是 set /p 接收到空输入时不会清空该变量原有值,二是无法一步到位地完成变量赋值、加前后缀、切割等等复杂动作。

CrLf 发表于 2011-7-19 13:39

[b] [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=86534&ptid=13327]12#[/url] [i]mxxcgzxxx[/i] [/b]


刚刚又去向无所不能的寒夜版主请教,我们原来以为 pause 会把紧随其后的 0D 0A 整个吞掉(因为曾经尝试用 pause 取换行符无果),但是12楼的代码举了个反例,这实在让我想不通,难道 pause 能提前判断下一行是否非空、当下一行不为空时则只吞 0D 吗?

后来找到了一个更为合理的假设,那就是 pause 本来就只吞碰到的第一个字符,此处的第一个字符也就是回车符 0D,而 set /p 继续接收第二行输入时接到了 0A ( 0D 0A,所以出现了换行效果。但是当第二行也是空行时,set /p 接收到的就是 0A 0D 0A,我们猜测 set /p 默认不会将单纯的换行符 0A 设为变量,所以 set /p 赋值为空。

做了个实验证明这一点:[code]@echo off


(for /l %%a in (1 1 10) do (
pause>nul
pause>nul
rem 用两个pause测试,看究竟是否吞了两组 0D 0A,如果 pause 是吞整个 0D 0A,那结果应该不会出现空行或者带换行符的变量
set /p .%%a=))<%0
set.
pause[/code]结果果然空了一行,证明每个 pause 确实只是取走紧随其后其后的那个字符,而非能够“预知”下一行的内容。

mxxcgzxxx 发表于 2011-7-19 15:47

[i=s] 本帖最后由 mxxcgzxxx 于 2011-7-19 15:49 编辑 [/i]

[b] [url=http://www.bathome.net/redirect.php?goto=findpost&pid=86617&ptid=13327]21#[/url] [i]zm900612[/i] [/b]
听起来是这个理,但下面这个情况怎么解释呢?[code]@echo off



(for /l %%a in (1 1 10) do (
pause>nul
rem 用两个pause测试,看究竟是否吞了两组 0D 0A,如果 pause 是吞整个 0D 0A,那结果应该不会出现空行或者带换行符的变量
set /p .%%a=))<%0
set.>1.txt
pause
[/code]输出的1.txt为
[quote].1=echo off
.4=for /l %%a in (1 1 10) do (
.5=ause>nul
.6=em 用两个pause测试,看究竟是否吞了两组 0D 0A,如果 pause 是吞整个 0D 0A,那结果应该不会出现空行或者带换行符的变量
.7=et /p .%%a=))<%0
.8=et.>1.txt
.9=ause
[/quote]
按理应该是下面这样取值的啊,为什么到3行出错了?然道说第三行的 0D 0A 可以用两次
[quote]@echo off 0D 0A
0D 0A
0D 0A
0D 0A
(for /l %%a in (1 1 10) do ( 0D 0A
pause>nul0D 0A
rem 用两个pause测试,看究竟是否吞了两组 0D 0A,如果 pause 是吞整个 0D 0A,那结果应该不会出现空行或者带换行符的变量0D 0A
set /p .%%a=))<%0 0D 0A
set.>1.txt 0D 0A
pause 0D 0A

.1=echo off
.2=0A 0D 0A
.3=0A
for /l %%a in (1 1 10) do (
.4=ause>nul
...[/quote]

mxxcgzxxx 发表于 2011-7-19 15:58

有半个换行符的值写入文本后会出现一个像退格符的黑块,但我发不上论坛,
可以对TXT文本进行复制并写到批处理里面,很好用也
但无法通过变量截取的方式获得有点可惜!

CrLf 发表于 2011-7-19 16:13

[b] [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=86628&ptid=13327]22#[/url] [i]mxxcgzxxx[/i] [/b]


诡异,测试后发现一次循环中只有一个 pause 时,连续空行数以一种奇怪的规律影响着变量的赋值:当连续空行数量为1、4、6、8...等数字时,会出现行首带有换行符的变量,这究竟是什么原因导致的呢...我也想不通了

mxxcgzxxx 发表于 2011-7-19 16:29

[i=s] 本帖最后由 mxxcgzxxx 于 2011-7-19 17:05 编辑 [/i]

[b] [url=http://www.bathome.net/redirect.php?goto=findpost&pid=86633&ptid=13327]24#[/url] [i]zm900612[/i] [/b]


那可以这样理解吗? 0D 0A 和0A 0D 都可以起到结束SET/P的输入过程
三行空行时
0D 0A
0D 0A
0D 0A
第一个0D被吃  SET/P得到0A 0D (强行终结)
第二个0A被吃   SET/P得到0D 0A (完整)
这样还能解释为什么三个空行被赋值两次
0A 0D 的组合有没有代表什么?
5个空行情况:
吃 ---- 留
0D---0A| 0D
0A|---0D  0A|
0D---0A| 0D
0A|---文本,所以正常不换行

以此类推,基本都合理了
1空行:0A 换行文本
2空行:完整文本
3空行:文本少头一字符
4空行:0A 换行文本
5空行:完整文本
。。。三个空行一个循环,所以:
1,4,7,10。。。为换行文本
2,5,8,11。。。为不少字的完整文本
0,3,6,9。。。为少头一字符的文本

刚才测试了下,完全符合这个规律!

CrLf 发表于 2011-7-19 17:24

[i=s] 本帖最后由 CrLf 于 2011-7-21 16:23 编辑 [/i]

[b] [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=86638&ptid=13327]25#[/url] [i]mxxcgzxxx[/i] [/b]


好!确实很有可能,测试代码如下:[code]@echo off
set x0a=^



::空行请自行添加
for /f %%a in ('copy /z %~s0 nul') do set x0d=%%a
cmd /v:on /c echo abc!x0a!!x0d!123!x0a!!x0d!>1.txt
(for /l %%a in (1 1 10) do set /p .%%a=)<1.txt
set.
pause>nul[/code]证明确实是以三行为一周期(汗一个,早先对此的测试结果是忘了加上被换行的那一行的,所以当时测试所得的周期很没有规律...误导人啊误导人),而且很有可能确实是像老兄说的那样,只要碰到一组 0D 0A,无论它们字符顺序如何,都能结束 set /p 的输入行为。

可用如下代码进行验证:[code]@echo off&setlocal enabledelayedexpansion
set a=^


(for /f %%a in ('copy /z %0 nul') do set b=%%a
set<nul /p=赋值成功!a!!b!赋值失败)>1.txt
set /p e=<1.txt
echo !e!
pause
echo d|debug 1.txt
::如果未出现赋值失败的字眼则代表 0A 0D 成功地结束了 set /p 的输入,结果证明确实如此[/code]越来越完善了

mxxcgzxxx 发表于 2011-7-19 19:41

[i=s] 本帖最后由 mxxcgzxxx 于 2011-7-21 16:50 编辑 [/i]

用提取的换行符玩下,虽然不知实用性在哪方面可以应用?
因为论坛会吃单空格行,所以我使用:号[code]

:
@echo off
::获取0A换行符
(pause>nul&set /p a=)<%0
echo 你好%a%我在哪?
pause>nul[/code]由于半个换行让“我在哪?”进行了无间道,不存在的东西
但开了变量延时后就不一样了[code]

:
@echo off
setlocal enabledelayedexpansion
::获取0A换行符
(set/p=&pause>nul&set /p a=)<%0
echo 你好!!a!我在哪啊?!a!你也不知道吗?!a!真是可惜……
pause>nul
set "b=123!a!456!a!789"
echo !b!
pause>nul
[/code]效果不是太理想但也很好了,一次三行内容,就是后面的每行多一个符号,可以加个退格符就可以了!!
而且可以通过赋值传达给别的函数,但一定要开变量延时和加上一个退格符!

[size=5][b][color=Blue]我也搜索了论坛,应该来说这个方法是快而简便获取换行符的方法,
又一个新技术诞生了哈![/color][/b][/size][code]

:
@echo off
setlocal enabledelayedexpansion
::获取0A换行符
(pause>nul&set /p a=)<%0
::通过赋值用退格符将换行符后的空格修整得到完整实用的换行符
set "b=!a!"
echo !b!123456!b!789
pause>nul[/code]

raymai97 发表于 2011-8-22 10:12

[b]回复 [url=http://bathome.net/redirect.php?goto=findpost&pid=86662&ptid=13327]27#[/url] [i]mxxcgzxxx[/i] [/b]


    其实我有些混乱了,你的代码的意思是这样么?[code](pause>nul&set /p a=)<%0[/code]利用批处理开头来获取换行字符和空格字符[code]set "b=!a!"[/code]换行+空格+退回字符=换行+不会再退回的退回字符=完整实用的换行符?

就达成了0d 0a组合的目的?

netbenton 发表于 2011-9-3 23:02

这个真的是新发现,竟然还支持嵌套,看来多个文件合并也可以了[code]@echo off
(set/p a1=

   (set /p b1=
   set /p b2=
   )<bb.txt

set/p a2=)<aa.txt


set a
set b

pause[/code]

DAIC 发表于 2011-9-3 23:46

[b]回复 [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=91437&ptid=13327]30#[/url] [i]netbenton[/i] [/b]


版主请帮忙看看这个合并文件时处理特殊字符的问题吧
[url]http://bbs.bathome.net/thread-13735-1-1.html[/url]

页: [1] 2

Powered by Discuz! Archiver 7.2  © 2001-2009 Comsenz Inc.