ファイルディスクリプタとリダイレクト関連 ファイルディスクリプタ番号とは †ファイルディスクリプタとは、プログラムがアクセスするファイルや、コンソール等 のデバイスを仮想化して識別するために用いる識別子。 0から順番に整数の番号が割り当てられる。 標準では、0が標準入力、1が標準出力、2が標準エラー出力に割り当てられ、 事前に CON デバイスがオープンされている。 3番以降は、プログラムがオープンするファイル等に割り当てられる。 リダイレクトとパイプ †記号 < によって入力のリダイレクト、> によって出力のリダイレクトが出来るが、
それぞれ0番、1番のファイルディスクリプタが対象となる。 リダイレクト先は、ファイルや CON や NUL 等のデバイスの他、他のディスクリプタと 同じと言う指定が出来る。 例えば、標準出力と標準エラー出力の両方を同じファイルにリダイレクトしたいとき、 dir xxx >file 2>&1 と書く(順序が重要)。 また、標準出力は | によるパイプ機能で他のプログラムの標準入力に渡すことが出来る。標準エラー出力もパイプで渡したい場合は、 route 2>&1 | more のように標準エラー出力を標準出力と同じものにリダイレクトしてパイプする。 ちなみに、1だけをファイルに書きたい場合、 echo 1>file では、1がディスクリプタ番号と見なされるため駄目で、 echo ^1>file と、^ で 1 をクォートするか、 >file echo 1 と書く必要がある(次項も参照)。 リダイレクトの記述位置 †リダイレクトは、コマンドのどこに書いても良い。 echo ABC>file.txt → ABC が書き込まれる echo ABC >file.txt → ABC の後ろに空白がついて書き込まれる echo >file.txt ABC → 空白が ABC の前について書き込まれる >file.txt echo ABC → ABC が書き込まれる >file.txt @echo ABC → エコー抑止の@は文頭に書くのでこれは誤り @>file.txt echo ABC → エコー抑止はこう書く echo の例を示したが他のコマンドでも同じである。ただし、for や if のように 構造を持った構文全体をリダイレクトするには、( ) で囲むことが必要。 >ping.out ping %HOST% → 正しい >file.txt for %%A in (*) do echo %%A → 誤り for >file.txt %%A in (*) do echo %%A → 誤り for %%A in (*) do >>file.txt echo %%A → echoに対してのリダイレクトとして正しい >file.txt (for %%A in (*) do echo %%A) → 正しい echo で複数行を1行ずつファイルに書く場合、 > tmp1.bat echo @echo off >>tmp1.bat echo setlocal >>tmp1.bat echo set N=0 >>tmp1.bat echo for /f "delims=" %%%%A in (%%1) do set /a N+=1 のように行頭に書くと見やすい。 後ろに書くと、リダイレクトの位置が縦に揃わないので見にくくなる。 (縦にそろえると、余分な空白が後ろについてしまう) または、 (echo @echo off echo selocal echo set N=0 echo for /f "delims=" %%%%A in (%%1^) do set /a N+=1) >tmp1.bat でも良いが、途中の ) を ^ でクォートする必要がある。 type NUL >out.txt for /l %%I in (1,1,10) do echo %%I>>out.txt は、 (for /l %%I in (1,1,10) do echo %%I) >out.txt と、for文全体を ( ) で囲んでリダイレクトしたほうがきれいだろう。 また、 set AA=A 1 echo.%AA%>temp では、AA の末尾にある 1 がファイルディスクリプタ番号と見なされて 1 はファイルに書き込まれない。このように中身が何であるかわからない環境変数の値echoしてリダイレクトする時は set AA=A 1 >temp echo.%AA% とする必要がある。 |