asc*_*pfl 5 windows cmd pipe batch-file
假设我们有一个文本文件sample.txt:
Run Code Online (Sandbox Code Playgroud)one two ...
现在我们要删除第一行:
Run Code Online (Sandbox Code Playgroud)two ...
一个快速的方式做到这一点是使用输入重定向,set /P以及findstr1(我知道有使用其他方法more或for /F,但让我们忘记他们现在):
@echo off
< "sample.txt" (
set /P =""
findstr "^"
)
Run Code Online (Sandbox Code Playgroud)
输出将按预期进行.
然而,当我更换输入重定向为什么是空的输出<通过type与管道|:
@echo off
type "sample.txt" | (
set /P =""
findstr "^"
)
Run Code Online (Sandbox Code Playgroud)
当我更换set /P =""的pause > nul,输出的是什么,我期待的-输入文件输出,但与第一行的丢失的第一个字符(因为它是由消耗pause).但为什么set /P似乎消耗所有东西而不是像重定向<方法一样只消耗第一行?那是一个错误吗?
对我来说,似乎set /P无法充分初始化到管道数据的读指针.
我在Windows 7和Windows 10上看到了这种奇怪的行为.
变得更加奇怪:当多次调用包含管道的脚本时,例如通过类似循环for /L %I in (1,1,1000) do @pipe.bat,并且输入文件包含大约十五行或更多,有时(几千次中的几次)输入文件的片段是回; 那个片段每次都完全一样; 似乎开头总共缺少80个字节.
1) findstr挂起,以防最后一行没有被换行符终止,所以让我们假设这样.
检索数据时,set /p尝试使用来自stdin的数据填充1023字符缓冲区(如果可用).一旦读取操作结束,就会搜索第一行结束,一旦找到它(或者已经到达缓冲区的末尾),SetFilePointer就会调用API以在读取行结束后重新定位输入流指针.这样,下一个读操作将开始在读取线之后检索数据.
当磁盘文件与输入流关联时,这可以完美地工作,但正如Microsoft在SetFilePointer文档中所述
该HFILE参数必须是指存储在探寻设备上的文件; 例如,磁盘卷.调用SetFilePointer带有手柄的非探寻设备功能,如管道或通信设备不被支持,即使SetFilePointer函数不能返回一个错误.在这种情况下,SetFilePointer函数的行为是未定义的.
发生的事情是,虽然没有产生任何错误,但当stdin与管道相关联时,重新定位读指针的调用失败,指针不会被移回,并且1023字节(或可用读取字节数)保持读取.
编辑以回应Aacini请求
该set命令由eSet函数处理,该函数调用SetWork以确定set将执行哪种类型的命令.
因为它是set /p在SetPromptUser函数被调用,并从该函数的ReadBufFromInput函数被调用
add esp, 0Ch
lea eax, [ebp+var_80C]
push eax ; int
push 3FFh ; int
lea eax, [ebp+Value]
push eax ; int
xor esi, esi
push 0FFFFFFF6h ; nStdHandle
mov word ptr [ebp+Value], si
call edi ; GetStdHandle(x) ; GetStdHandle(x)
push eax ; hFile
call _ReadBufFromInput@16 ; ReadBufFromInput(x,x,x,x)
Run Code Online (Sandbox Code Playgroud)
它3FFh从标准输入句柄请求(1023)字符(0FFFFFFF6h= -10= STD_INPUT_HANDLE)
ReadBufFromInput使用GetFileTypeAPI来确定它是应该从控制台还是从文件中读取
; Attributes: bp-based frame
; int __stdcall ReadBufFromInput(HANDLE hFile, int, int, int)
_ReadBufFromInput@16 proc near
hFile= dword ptr 8
; FUNCTION CHUNK AT .text:4AD10D3D SIZE 00000006 BYTES
mov edi, edi
push ebp
mov ebp, esp
push [ebp+hFile] ; hFile
call ds:__imp__GetFileType@4 ; GetFileType(x)
and eax, 0FFFF7FFFh
cmp eax, 2
jz loc_4AD10D3D
Run Code Online (Sandbox Code Playgroud)
并且,在这种情况下,它是一个管道(GetFileType返回3)代码跳转到该ReadBufFromFile函数
; Attributes: bp-based frame
; int __stdcall ReadBufFromFile(HANDLE hFile, LPWSTR lpWideCharStr, DWORD cchWideChar, LPDWORD lpNumberOfBytesRead)
_ReadBufFromFile@16 proc near
var_C= dword ptr -0Ch
cchMultiByte= dword ptr -8
NumberOfBytesRead= dword ptr -4
hFile= dword ptr 8
lpWideCharStr= dword ptr 0Ch
cchWideChar= dword ptr 10h
lpNumberOfBytesRead= dword ptr 14h
Run Code Online (Sandbox Code Playgroud)
此函数将调用ReadFileAPI函数以检索指定数量的字符
push ebx ; lpOverlapped
push [ebp+lpNumberOfBytesRead] ; lpNumberOfBytesRead
mov [ebp+var_C], eax
push [ebp+cchWideChar] ; nNumberOfBytesToRead
push edi ; lpBuffer
push [ebp+hFile] ; hFile
call ds:__imp__ReadFile@20 ; ReadFile(x,x,x,x,x)
Run Code Online (Sandbox Code Playgroud)
迭代返回的缓冲区以搜索行尾,一旦找到它,输入流中的指针就会在找到的poisition之后移动
.text:4AD06A15 loc_4AD06A15:
.text:4AD06A15 cmp [ebp+NumberOfBytesRead], 3
.text:4AD06A19 jl short loc_4AD06A2D
.text:4AD06A1B mov al, [esi]
.text:4AD06A1D cmp al, 0Ah
.text:4AD06A1F jz loc_4AD06BCF
.text:4AD06A25
.text:4AD06A25 loc_4AD06A25:
.text:4AD06A25 cmp al, 0Dh
.text:4AD06A27 jz loc_4AD06D14
.text:4AD06A2D
.text:4AD06A2D loc_4AD06A2D:
.text:4AD06A2D movzx eax, byte ptr [esi]
.text:4AD06A30 cmp byte ptr _DbcsLeadCharTable[eax], bl
.text:4AD06A36 jnz loc_4AD12018
.text:4AD06A3C dec [ebp+NumberOfBytesRead]
.text:4AD06A3F inc esi
.text:4AD06A40
.text:4AD06A40 loc_4AD06A40:
.text:4AD06A40 cmp [ebp+NumberOfBytesRead], ebx
.text:4AD06A43 jg short loc_4AD06A15
.text:4AD06BCF loc_4AD06BCF:
.text:4AD06BCF cmp byte ptr [esi+1], 0Dh
.text:4AD06BD3 jnz loc_4AD06A25
.text:4AD06BD9 jmp loc_4AD06D1E
.text:4AD06D14 loc_4AD06D14:
.text:4AD06D14 cmp byte ptr [esi+1], 0Ah
.text:4AD06D18 jnz loc_4AD06A2D
.text:4AD06D1E
.text:4AD06D1E loc_4AD06D1E:
.text:4AD06D1E mov eax, [ebp+var_C]
.text:4AD06D21 mov [esi+2], bl
.text:4AD06D24 sub esi, edi
.text:4AD06D26 inc esi
.text:4AD06D27 inc esi
.text:4AD06D28 push ebx ; dwMoveMethod
.text:4AD06D29 push ebx ; lpDistanceToMoveHigh
.text:4AD06D2A mov [ebp+cchMultiByte], esi
.text:4AD06D2D add esi, eax
.text:4AD06D2F push esi ; lDistanceToMove
.text:4AD06D30 push [ebp+hFile] ; hFile
.text:4AD06D33 call ds:__imp__SetFilePointer@16 ; SetFilePointer(x,x,x,x)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
135 次 |
| 最近记录: |