2017-05-09 17 views
4

確かに、コマンドプロンプトからEOFを送信するには、を入力してを入力し、続いてをCtrl-Zにします。改行なしでコマンドプロンプトからEOFを送信する方法*?

C:\> type con > file.txt 
line1 
line2 
^Z 

これは動作し、file.txtline1\r\nline2\r\nが含まれています。しかし、最後の改行なしで同じことをするには、file.txtにはline1\r\nline2が含まれていますか?

Linuxでは、解決方法はCtrl-Dを2回と打つことです。しかし、Windows上で同等のものは何ですか?コマンドプロンプトは、EOFを送信せずに行の最後に^Zをうまく印刷します。 (あなたはをEnterキーを押す場合は、その後、任意の^Zのリテラルのエスケープ文字としてファイルに書き込まれますと入力した!)

Windows上でこれを行う方法はありません場合は、なぜ?


https://askubuntu.com/questions/118548/how-do-i-end-standard-input-without-a-newline-character

+6

'copy con file.txt'も必要なように動作するはずです。 – eryksun

答えて

4

ターゲットファイルがconないので、コマンドtype con > file.txtは、CMDシェルで^Zのための特別な処理を持っていないとtypeコマンドはUnicodeで実行されませんでした(UTF-16LE)出力モードです。この場合、^Z処理だけがReadFile呼び出し自体にあります。コンソール入力バッファの場合、行が^Zで始まる場合は0バイトを返すように文書化されていません。

読み込みバイト数(lpNumberOfBytesRead)が出力パラメータとして参照によって返される4番目の引数(x64のレジスタr9)であることに注目して、デバッガをアタッチして調べてみましょう。

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 

上記のように、"line1\r\n"は7文字です。次のは"\x1aline2\r\n"を入力して、何バイトReadFile見てみましょうと伝え読み:

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 

あなたは上記を参照したように、この時間は、それはすなわちEOF、0バイトを読み取ります。 ^Zの後に入力されたものはすべて無視されました。

ただし、入力バッファに^Zが表示されている場合は、この動作を一般的に行うことをお勧めします。 typeがこれを行いますが、Unicodeモードで実行された場合、つまりcmd /u /c type con > file.txtになります。この場合、cmdには^Zの入力をスキャンする特別な処理があります。しかし、私はあなたがUTF-16LEファイルを望んでいないと思っています。特に、cmdはBOMを書いていないので、エディタがUTFエンコーディングを検出できるようになっています。

copy con file.txtがあなたの望むものとまったく同じことが起こるので、運が良かったです。内部的にはcmd!ZScanAを呼び出して各行をスキャンして^Z文字を探します。これをデバッガで実際に確認できますが、今回は完全に文書化されていません。調べると、この関数の3番目のパラメータ(x64のレジスタr8)は、in-out引数として読み取られたバイト数です。

のは、7文字列"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 

を、スキャンした長さは7つの文字のまま:

0:000> pt 
cmd!ZScanA+0x4f: 
00007ff7`cf4c271f c3    ret 
0:000> dd 68c5d1ea64 l1 
00000068`c5d1ea64 00000007 
0:000> g 

次は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 

今回は、スキャンされたlen

0:000> pt 
cmd!ZScanA+0x4f: 
00007ff7`cf4c271f c3    ret 
0:000> dd 68c5d1ea64 l1 
00000068`c5d1ea64 00000005 

我々はfile.txtをはそれが12バイトで、あることを期待:GTHは^Zが先行している唯一の5つの文字である

C:\Temp>for %a in (file.txt) do @echo %~za 
12 

より一般的には、Windowsのコンソールプログラムの場合Unix端末の動作を近似するCtrl + D処理を実装したい場合は、ワイド文字コンソール機能ReadConsoleWを使用して、CONSOLE_READCONSOLE_CONTROL構造体をpInputControlとして渡すことができます。この構造体のdwCtrlWakeupMaskフィールドは、どの制御文字が読み込みを直ちに終了するかを設定するビットマスクです。たとえば、ビット4はCtrl + Dを有効にします。あなたは上記の例でこれを見ることはできませんが、この読み出しはすぐにでもEnterを押しせずに、Ctrlキー+ Dを押して終了した

C:\Temp>.\test 
Enter some text: line1 
You entered: line1\x04 

:私はこのケースを示して簡単なテストプログラムを書きました。制御文字('\x04')の^Dは入力バッファに残ります。これは、複数の制御文字に対して異なる動作が必要な場合に便利です。

+0

ありがとう@eryksun!フードの下で何が起こっているかについての非常に徹底的かつ興味深い分析... – mksios

関連する問題