La commande type con > file.txt
n'a pas de traitement spécial pour ^Z
dans le shell cmd, car le fichier cible n'est pas con
et la commande type
n'a pas été exécutée en Unicode (UTF-16LE) mode de sortie. Dans ce cas, la seule manipulation ^Z
est dans l'appel ReadFile
lui-même, qui pour un tampon d'entrée de console a un comportement non documenté pour renvoyer 0 octets lus si une ligne commence par ^Z
.
Examinons ceci avec un débogueur attaché, notant que le nombre d'octets lus (lpNumberOfBytesRead
) est le 4ème argument (registre r9 en x64), qui est renvoyé par référence comme paramètre de sortie.
C:\Temp>type con > file.txt
Breakpoint 1 hit
KERNELBASE!ReadFile:
00007ffc`fb573cc0 48895c2410 mov qword ptr [rsp+10h],rbx
ss:00000068`c5d1dfa8=000001e3000001e7
0:000> r r9
r9=00000068c5d1dfd0
0:000> pt
line1
KERNELBASE!ReadFile+0xa9:
00007ffc`fb573d69 c3 ret
0:000> dd 68c5d1dfd0 l1
00000068`c5d1dfd0 00000007
Comme vous le voyez ci-dessus, la lecture "line1\r\n"
est de 7 caractères, comme prévu. Ensuite, nous allons entrer "\x1aline2\r\n"
et de voir combien d'octets ReadFile
lectures seraient:
0:000> g
Breakpoint 1 hit
KERNELBASE!ReadFile:
00007ffc`fb573cc0 48895c2410 mov qword ptr [rsp+10h],rbx
ss:00000068`c5d1dfa8=0000000000000000
0:000> r r9
r9=00000068c5d1dfd0
0:000> pt
^Zline2
KERNELBASE!ReadFile+0xa9:
00007ffc`fb573d69 c3 ret
0:000> dd 68c5d1dfd0 l1
00000068`c5d1dfd0 00000000
Comme vous le voyez ci-dessus, cette fois-ci lit 0 octets, à savoir EOF. Tout tapé après ^Z
a été simplement ignoré. Cependant, ce que vous voulez à la place est d'obtenir ce comportement en général, où ^Z
apparaît dans le tampon d'entrée. type
le fera pour vous, mais seulement si elle est exécutée en mode Unicode, c'est-à-dire cmd /u /c type con > file.txt
. Dans ce cas, cmd a une manipulation spéciale pour analyser l'entrée pour ^Z
. Mais je parie que vous ne voulez pas un fichier UTF-16LE, d'autant plus que cmd n'écrit pas de nomenclature pour permettre aux éditeurs de détecter le codage UTF.
Vous avez de la chance, car il arrive que copy con file.txt
fait exactement ce que vous voulez. En interne, il appelle cmd!ZScanA
pour numériser chaque ligne pour un caractère ^Z
. Nous pouvons voir cela dans l'action dans le débogueur, mais cette fois nous sommes dans un territoire complètement sans papiers. Lors de l'inspection, il apparaît que le troisième paramètre de cette fonction (registre r8 en x64) est le nombre d'octets lus en tant qu'argument in-out.
Commençons à nouveau en entrant la chaîne 7 caractères "line1\r\n"
:
C:\Temp>copy con file.txt
line1
Breakpoint 0 hit
cmd!ZScanA:
00007ff7`cf4c26d0 48895c2408 mov qword ptr [rsp+8],rbx
ss:00000068`c5d1e9d0=0000000000000000
0:000> r r8; dd @r8 l1
r8=00000068c5d1ea64
00000068`c5d1ea64 00000007
En sortie, la longueur numérisée reste 7 caractères:
0:000> pt
cmd!ZScanA+0x4f:
00007ff7`cf4c271f c3 ret
0:000> dd 68c5d1ea64 l1
00000068`c5d1ea64 00000007
0:000> g
Entrez ensuite la chaîne de caractères 23 (0x17) "line2\x1a Ignore this...\r\n"
:
line2^Z Ignore this...
Breakpoint 0 hit
cmd!ZScanA:
00007ff7`cf4c26d0 48895c2408 mov qword ptr [rsp+8],rbx
ss:00000068`c5d1e9d0=0000000000000000
0:000> r r8; dd @r8 l1
r8=00000068c5d1ea64
00000068`c5d1ea64 00000017
Cette fois, la numérisation len GTH est seulement les 5 caractères qui précèdent le ^Z
:
0:000> pt
cmd!ZScanA+0x4f:
00007ff7`cf4c271f c3 ret
0:000> dd 68c5d1ea64 l1
00000068`c5d1ea64 00000005
Nous file.txt attendre à être 12 octets, il est:
C:\Temp>for %a in (file.txt) do @echo %~za
12
Plus généralement, si un programme de console Windows veut mettre en œuvre la gestion Ctrl + D qui se rapproche du comportement d'un terminal Unix, il peut utiliser la fonction de console de caractères larges ReadConsoleW
, en passant une structure CONSOLE_READCONSOLE_CONTROL
par référence pInputControl
. Le champ dwCtrlWakeupMask
de cette structure est un masque de bits qui définit les caractères de contrôle qui terminent immédiatement la lecture. Par exemple, le bit 4 active Ctrl + D. J'ai écrit un programme de test simple qui démontre ce cas:
C:\Temp>.\test
Enter some text: line1
You entered: line1\x04
Vous ne pouvez pas le voir dans l'exemple ci-dessus, mais cette lecture a été immédiatement interrompue en appuyant sur Ctrl + D, sans même en appuyant sur Entrée. Le caractère de contrôle ^D
(c'est-à-dire '\x04'
) reste dans le tampon d'entrée, ce qui est utile dans le cas où vous souhaitez un comportement différent pour plusieurs caractères de contrôle.
'copy con file.txt' devrait également fonctionner comme vous le souhaitez. – eryksun