バッチファイルで<&4と4<%1は何をしているの?

このQ&Aのポイント
  • バッチファイルで標準出力とエラー出力をファイルに書き出す方法を理解していますが、数値が3以上で使用されているコードを見かけました。
  • 具体的なコード例としては、「SET /P s1= >NUL <&4」という行で、4というハンドルを用いて標準入力から読み取りを行っています。
  • このコードでは、%1(file1.txt)ファイルの行を順番に4というハンドルに読み込み、環境変数s1に代入しています。このような使用法についての詳しい解説はありませんが、バッチファイルの応用的な使用例と言えます。
回答を見る
  • ベストアンサー

バッチファイルで<&4と4<%1は何をしているの?

MS-DOSバッチファイルで、 コマンド1 > ファイル名 2>&1 というような書き方をして、 標準出力だけでなくエラー出力もファイルに書き出すことが できることは理解しています。 そして、数値は0,1,2の3つがあり、各々、 ハンドルSTDIN(キーボード入力) ハンドルSTDOUT(コマンドプロンプトウィンドウへの出力) ハンドルSTDERR(コマンドプロンプトウィンドウへのエラーの出力) であることも理解しています。 しかし、 この数値が3以上で使用されているコードを見かけました。 例えば、 ネット上に以下のコードがあったのですが、 SET /P s1= >NUL <&4 の「>NUL」の部分は、 メッセージが画面に表示されないようにしていると思いますが、 「&4」の部分と 最後の行の4<%1の「4」の部分は何をしているのでしょうか。 実際に動かしてみると、 %1(file1.txt)ファイルの各行が、1行ずつ、 4という名前の変数(ハンドル?)に順番に入っていき、 &4の部分でそれを取り出して、 環境変数s1に代入(セット)しているように見えます。 私は、バッチファイルで、 このような(3以上の数値を使った)使用法を いままでに見たことがありませんでした。 このような使い方を詳しく解説しているサイト がありましたら教えてください。 よろしくお願いします。(Windows10) ---Paste.CMD--------------------------------- @ECHO OFF SETLOCAL ENABLEDELAYEDEXPANSION (FOR /F %%0 IN ('FIND /C /V ""') DO SET a1=%%0) <%1 (FOR /F %%0 IN ('FIND /C /V ""') DO SET a2=%%0) <%2 IF %a1% LSS %a2% SET /A a1=a2 (FOR /L %%k IN (1,1,%a1%) DO ( SET s1= SET s2= SET /P s1= >NUL <&4 SET /P s2= >NUL <&5 ECHO:!s1! !s2! ) ) 4<%1 5<%2 ------------------------------------ 使用例 paste file1.txt file2.txt ------------------------------------

質問者が選んだベストアンサー

  • ベストアンサー
  • notnot
  • ベストアンサー率47% (4847/10260)
回答No.7

そもそもfindstrはファイルディスクリプター(以下fdと略)0からデータを読むように作られているプログラムです。 で、fdの1に処理結果のデータを書きます。 findstrに限らず多くのコマンドもそうです。 例えばechoはfdの1に書きます。 ということがそもそも理解できていなかったということでしょうかね?<&0 が省略されているわけでは無い。 <&0 や >&1 は無意味なのでCMD.EXEではエラーになるようです。

ID_20150222
質問者

お礼

なるほど。そういったことでしたか。 これで①は解決しました。 もし、①の回答が、 ディスクリプター0だからできないという回答だった場合、 0以外(例えば3など)ではできるのですかというのが②なので、 今回の回答で②も解決です。 ありがとうございました。

その他の回答 (6)

  • notnot
  • ベストアンサー率47% (4847/10260)
回答No.6

① 同じ番号だとエラーになるようですね。 ② ちょっと何を言ってるのか分かりません。 やってみれば良いのでは?

ID_20150222
質問者

お礼

質問の内容が分かりにくくて申し訳ありませんでした。 再度、説明されて頂きたく思いますが、 ②は①の回答結果によりますので、 まず①のみを説明されて頂きます。 最初にこの質問をした背景を述べておきます。 Paste.CMDには3つのFOR文がありますが、 3番目のFOR文は、 (FOR … SET /P s1= >NUL <&4 …) 4<%1 … となっていて、4<%1 と <&4 の部分があり、 4<%1の部分で、%1がファイルディスクリプタ4に取り込まれて、 <&4の部分で、ファイルディスクリプタ4から取り出しているので、 分かりやすいのですが、 1番目と2番目のFOR文は、 (FOR /F %%0 IN ('FIND /C /V ""') DO SET a1=%%0) <%1 となっていて、<%1 のみで <&の部分がなく、 どのようになっているのかがよく分かりませんでしたので、 今回のような質問をしました。 頂いた回答No4で、 <%1 は 0<%1 の 0 が省略されていることを教えて頂きましたので、 同様に、<&0 の部分も省略されているのではないかと考えて、 おそらく、省略しないと、 FIND /C /V "" <&0 のようになるのではないかと思ったのですが、 これではエラーになりましたので、 1番目のFOR文で、<&0 を省略しないで記述するには、 どのように記述をすればよいかのを教えて頂きたくて、 回答No5の所で①のような質問をしました。 期待していた回答としては、 (FOR /F %%0 IN ('FIND /C /V ""' <&0) DO SET a1=%%0) 0<%1 というような回答を頂きたかったのですが・・・ ただし、このコードではエラーになりますので、 エラーにならないコードを教えて頂けないでしょうか。 よろしくお願いします。

  • notnot
  • ベストアンサー率47% (4847/10260)
回答No.5

> For文でのファイルディスクリプタの使い方を解説しているサイトがありましたら教えて頂けないでしょうか。 リダイレクトやファイルディスクリプタについて、for文だからと言って特別なことは何も無いです。他のコマンドにおけるリダイレクトやファイルディスクリプタと全く同じです。

ID_20150222
質問者

お礼

回答ありがとうございます。 リダイレクトやファイルディスクリプタについては、 for文でもfor文でなくても全く同じということですが、 (for文とは直接関係ないのかもしれませんが) 以下のことがよく分からないので、 もし、分かりましたら教えて頂けないでしょうか。 ①<&0を明示的に記述することはできるのでしょうか?  例えば、  (FOR /F %%0 IN ('FIND /C /V ""') DO SET a1=%%0) 0<%1  で、%1の値がファイルディスクリプタ0に入力された後、  ファイルディスクリプタ0に入った値を取り出すには、  <&0 と記述すると思われますが、  (FOR /F %%0 IN ('FIND /C /V ""') DO SET a1=%%0) 0<%1  で、<&0を記述するには、  どのように記述をすればよいのでしょうか。 ②ファイルディスクリプタの数字として、  3以上の値を指定しても0や1と同じように  使えうことができるのでしょうか?  例えば、  (FOR /F %%0 IN ('FIND /C /V ""') DO SET a1=%%0) 0<%1  で、ファイルディスクリプタの数字が、0ではなくて、3を使用して、  (①に相当する<&3も併用して)、記述することはできるのでしょうか。 よろしくお願いします。

  • notnot
  • ベストアンサー率47% (4847/10260)
回答No.4

ファイルディスクリプタは入出力では常に使います。 echo offを書かずに実行されるコマンドを表示させてみたことはないでしょうか? echo aaa >FILE という内容のバッチファイルを作って実行すると、 echo aaa 1>FILE と表示されます。リダイレクト記号にファイルディスクリプタの数字を書かないと出力は1、入力は0が自動的に設定されます。 また、set と set /p は違う命令なので、入れ替えると違う動作をします。それぞれの意味がわからないと言うことなんでしょうか? コマンドプロンプトでset /?と打つと、説明が表示されます。

ID_20150222
質問者

お礼

set /? で調べてみました。 SET [変数名=[文字列]] 変数名 環境変数名を指定します。 文字列 変数に割り当てる文字列を指定します。 SET /P 変数=[プロンプト文字列] ユーザーによって入力された入力行を変数の値として設定できるようにします。 リダイレクトによって入力された文字列を変数に設定するので、SETではなくSET /Pということですね。 ありがとうございました。

  • f272
  • ベストアンサー率46% (8008/17113)
回答No.3

> for文でのハンドルの使い方 for文で特有の使い方というのはありません。どこで使っても入出力をリダイレクトするということだけです。 例えば SET /P s1= >NUL <&4 で/pがついているのは「for文でのハンドルの使い方」とは何の関係もありません。/pがなければ「変数=設定する値」と書きますが、/pがあれば「変数=表示される文字列」となって設定する値の入力まちになります。この例ではそれが4番のファイルから与えられるということです。 ちなみに (FOR /F %%0 IN ('FIND /C /V ""') DO SET a1=%%0) <%1 であれば0<%1と書いてあるのと同じことです。0は省略可能だから<%1となっているのです。他の例と何もかわりはありません。

ID_20150222
質問者

お礼

回答ありがとうございます。 1番目、2番目のfor文と3番目のfor文は、 違うように見えるけれども、 数字や<&が省略されているだけで、 ファイルハンドルとリダイレクトの使い方自体は、 どちらも同じということですね。 それでも、まだよく分からないことがあります。 1番目の (FOR /F %%0 IN ('FIND /C /V ""') DO SET a1=%%0) 0<%1 では、3番目の<&4に相当する部分がありませんが、 省略すると、暗黙的に、 条件式('FIND /C /V ""')の部分が指定されるのでしょうか。 また、明示的に<&0を指定しようとすると、 (FOR /F %%0 IN ('FIND /C /V ""' <&0) DO SET a1=%%0) 0<%1 (FOR /F %%0 IN ('FIND /C /V "" <&0' ) DO SET a1=%%0) 0<%1 では、エラーになってしまいますが、 明示的に<&0を指定するにはどのように記述すればよいのでしょうか。 3番目の4を0や1に変えると正しく動作しなくなります。 0と1は入力用と出力用なので使えないのかなと思って、 (FOR /F %%0 IN ('FIND /C /V ""' <&6) DO SET a1=%%0) 6<%1 (FOR /F %%0 IN ('FIND /C /V "" <&6' ) DO SET a1=%%0) 6<%1 のようにしてみましたが駄目でした。 よろしくお願いします。

  • notnot
  • ベストアンサー率47% (4847/10260)
回答No.2

そういう数字を「ファイルディスクリプタ」といいます。 3以上のファイルディスクリプタは予約されてないので、自由にファイルに割り当てて使うことが出来ます。 (FOR /L %%k ~~~ SET /P s1= >NUL <&4 SET /P s2= >NUL <&5 ) 4<%1 5<%2 の部分で括弧内全体のリダイレクトとして、 4番ファイルディスクリプタが 引数1ファイル からの入力 5番ファイルディスクリプタが 引数2ファイルからの入力 にリダイレクトされているので、括弧内で4番から読めば引数1のファイルから読むことになります。 ・ファイルディスクリプタとは何か ・リダイレクトとは何か を知っていれば単なる応用です。 Linuxのシェルだともっと柔軟なことも出来ますね。

ID_20150222
質問者

お礼

ファイルディスクリプタというのですね。 for文でのファイルディスクリプタの使い方について よく分からないのですが、 例えば、 最初の2つのfor文は、 (FOR /F %%0 IN ('FIND /C /V ""') DO SET a1=%%0) <%1 というようにファイルディスクリプタは使っていないのに、 3つ目のfor文では、ファイルディスクリプタは使っていますが、 最初の2つのfor文でも、 ファイルディスクリプタを使ってできるのですか。 逆に、3つ目のfor文で、ファイルディスクリプタを使わずに できるのでしょうか。 また、SET s1= ではなく SET /P s1= を使っていますが、 SET s1= ではできないのでしょうか。 このあたりのことがよく分かっていません。 よろしくお願いします。

ID_20150222
質問者

補足

回答ありがとうございます。 3以上の時は特殊な使用法があると思っていましたので、 上記のような質問をしましたが、 質問の仕方がよくありませんでした。 For文でのファイルディスクリプタの使い方が よく分からないので、 For文でのファイルディスクリプタの使い方を 解説しているサイトがありましたら 教えて頂けないでしょうか。 なお、お礼の方のコメントは無視してください。 よろしくお願いします。

  • f272
  • ベストアンサー率46% (8008/17113)
回答No.1

あなたが推測していることの通りです。 4< とあればハンドル4に入力をリダイレクトしますし、 <&4 とあればハンドル4からの入力をリダイレクトします。 このように括弧で囲まれたブロックまたはサブルーチンの外側の未定義のハンドルにリダイレクトし、&表記を使用して既に開いているファイルを参照することができます。 ハンドルとして使える数字は0から9までですが、すでにあなたをもわかっているように0、1、2は標準入力、標準出力、エラー出力に結び付けられています。

ID_20150222
質問者

お礼

回答ありがとうございます。 3以上の時は特殊な使用法があると思っていましたので、 上記のような質問をしましたが、 質問の仕方がよくありませんでした。 for文でのハンドルの使い方についてよく分からないので、 解説しているサイトを教えて欲しかったのです。 例えば、 SET /P s1= >NUL <&4 の部分ですが、 SET s1=・・・ではできないのでしょうか。 なぜ/Pがついているのかがよく分かりません。 よろしくお願いします。

関連するQ&A

  • バッチファイルでの計算方法

    一行のみのtxtファイル(1111.txt)に日付 スペース 時間 スペース 値 が格納されています。 バッチファイルにて上記値に定数(6666)をかけ単位を追加して出力(2222.txt)したいとおもいます。 以下のように書いてみましたが どこが悪いかよくわかりません。 どなたかお教えいただきたいと思います @ECHO OFF FOR /F "eol=# tokens=1,2,3" %%a in (1111.txt) SET /A x=6666 SET y=%%c*%x% DO ECHO %%a %%b %%y >2222.txt

  • バッチファイルで条件によって書き出さないようにしたい

    temp.txtというファイルのカンマ4つめが同じだったらテキストに出力しないバッチファイルを作りたいと思っています。 set sbuf=test for /f "tokens=4 delims=, " %%a in (C:temp.txt) do ( set saddress=%%a if %sbuf% == %%a ( ) else ( set saddress=%%a findstr %saddress% C:\sip_cmail\ping_sip.txt >> C:\out.txt ) set sbuf=%%a ) と書いてみたのですが、動きません。 流れとしては、一巡目に通ったときの値をbufにいれておいて、二順目通ったときに比べ、同じだったら何もしないで次に行く、としたいのですが、、 括弧が何十にもなると出来ないのでしょうか。 よろしくお願い致します。

  • バッチファイルのfor文を使ってファイルサイズをMbyteで表したい。

    バッチファイルのfor文を使ってファイルサイズをMbyteで表したい。(WindowsXP) for文を使って、フォルダー内のファイル名とサイズ一覧を作ろうとしています。 1)for %%i in (c:\test\*.*) do echo %%i %%~zi>> c:\test\testfiles.txt で一応はできたのですが、これではファイルサイズがわかりにくいので、メガバイト単位にしたいのです。(だいたいわかればいいので1024で割るとかはしない) 2)for %%i in (c:\test\*.*) do echo %%i %%~zi/1000000>> c:\test\testfiles.txt 3)for %%i in (c:\test\*.*) do set /a x=%%~zi/1000000 & echo %%i %%x>> c:\test\testfiles.txt としてもうまくいきません。 %%~ziが数値でなく文字列のため、だと思うのですが、3)は%の付け方とかも間違ってそう。 どう書けばメガバイト単位で一覧を出せるでしょうか? あれ? 4)for %%i in (c:\test\* ) do if %%~zi GEQ 1000000 echo %%i>> c:\test\testfiles.txt とすれば1メガ以上のファイル名一覧が出ますね。 ということは%%~ziは数値なのか。  どなたか、どこが間違っているのか教えていただけないでしょうか

  • バッチファイル 文字列操作のやり方

    お世話になります。 バッチファイルのコマンドについてですが、 for文の中で 一番下の階層のファイル名の先頭5バイトが "abcde"のものだけ処理対象にしたいと考えています。 例えば、 C:\tempに以下のファイルがあったら C:\temp\abcdefg.txt    ・・・(1) C:\temp\xxxxxxx.txt    ・・・(2) C:\temp\abcde.txt    ・・・(3) C:\temp\abc.txt    ・・・(4) C:\temp\abcdezzzz.txt    ・・・(5) (1)、(3)、(5)だけを処理させたいと考えています。 実装方法として、以下を考えましたがうまくいきません。 dir /s /b /a-d C\Temp > file.txt for /f "delims=" %%F in (file.txt) do ( set A=%%~nF% if "%%A:~0,5%"=="abcde" ( <処理コマンド> ) ) おそらくfor文の中で何個も命令を記述できないということと、 パラメータ修飾子の指定が間違っているからだと思われますが、 うまくできない理由を知りたいです。 よろしくお願いいたします。

  • バッチファイルで2行にわたるコマンドを入力したいのですが

    バッチファイルで複数行にわたるコマンドを打ちたいのですが、方法がわからなくて困っています。 for /f "tokens=1,2,3 delims=/ " %%a in ('date /t') do ( set hinichi=%%a%%b ) "C:\Program Files\Lhaca\Lhaca.exe" "test%hinichi%01.txt" "test%hinichi%02.txt" ・・・・・・・ と31個のファイルを圧縮するバッチです。 体裁の問題ですが、 for /f "tokens=1,2,3 delims=/ " %%a in ('date /t') do ( set hinichi=%%a%%b ) "C:\Program Files\Lhaca\Lhaca.exe" ? "test%hinichi%01.txt" ? "test%hinichi%02.txt" ・・・ としたいのですが各行のつなぎの記号?がわかりません。 ご存知の方、よろしくお願いいたします。

  • バッチファイルのfor文の使い方がわかりません。

    バッチ初心者です。 指定したフォルダのテキストファイルを一括置換するバッチファイルを作成したのですが、 for文を使うところでつまづいてしました。 for文のin( )内にディレクトリを入れると失敗してしまいます。 失敗例↓ for %%f in (d:\aaa\*.txt) do ( set fname=%%f set fname=!fname:%1=%2! ren %%f !fname! ) for文を for %%f in (*.txt) にすると成功します。 IN( )内にディレクトリを入れると処理が失敗するのはなぜでしょうか?? helpを読んでもわかりません。 試しにオプション付けて for /r d:\aaa %%f in (*.txt) do echo %%f を実行すると成功するので、 for /r d:\aaa %%f in (*.txt) do ( ・・・・ ) にしてみましたが、成功しません。。。

  • バッチファイル 2ファイルをfor /f処理したい

    バッチファイルで別の2つのファイルを読み込んでfor /f処理するには 変換前のファイルのファイル名と 変換後のファイルのファイル名が それぞれ別のファイルに書かれていて この2つのファイルを読み込んで リネームするバッチファイルを 記述したいのですが 2つのfor /fを使った場合、 一方が他方にネストされてしまうのですが このような場合は どのように記述するのでしょうか。 例えば、 変換前のファイル名が書かれたファイル(s.txt)と 変換後のファイル名が書かれたファイル(d.txt) がある場合、 abc.txtをqrs.txt d f.txtをtuw.txt ghi.txtをx z.txt  : にリネームしたいのですが もちろんtest1.batではうまくいきません。 ---test1.bat------------------- for /f %%a in (s.txt) do for /f %%b in (d.txt) do ren "%%a" "%%b" ------------------------------ ---s.txt---------------------- abc.txt d f.txt ghi.txt : ---d.txt---------------------- qrs.txt tuw.txt x z.txt : ------------------------------ 以下の sd.txt のように1つのファイルにして test2.bat のようにすればできますが s.txt と d.txt の2つのファイルのままで処理するには どのように記述すればよいのでしょうか。 ---test2.bat------------------- for /f "tokens=1,2 delims=," %%a in (sd.txt) do ren "%%a" "%%b" ---sd.txt---------------------- abc.txt,qrs.txt d f.txt,tuw.txt ghi.txt,x z.txt : ------------------------------- よろしくお願いします。(Windows7)

  • バッチファイルで変数の内容変更

    以下のバッチファイルで,10回目のループで,ファイル名を入力している変数を 「out.txt」と変更したいのですが,変更前の「in.txt」と 出力されてしまいます。 どのように対処すれば宜しいでしょうか? よろしくお願いします。 @echo off set FLN=in.txt for /L %%N in ( 1 , 1 , 10 ) do ( echo %%N if "%%N" equ "10" ( echo 変更します set FLN= set FLN=out.txt ) echo %FLN% ) @echo on

  • バッチファイル内置換

    バッチファイルで、置換をしたいのですが、"="と"<"の置換が出来ません。 ping出力を「file.txt」へ保存し、保存した「file.txt」を一行づつ読み出し下記を実行しています。 for /f "delims=" %%a in ( orig ) do ( set line=%%a call :sub ) :sub set tmp=%line% set tmp=%tmp:<=,% set tmp=%tmp:= =,,% set tmp=%tmp:"時間" =,% set tmp=%tmp:ms=,ms% echo %tmp%>>%CSV_Name% goto :EOF :end 置換出来ないのは、"=" と "<"の文字だけが置換出来ません。 ネットで調べたのですが、"^" でエスケープしても、""二重引用部でくくっても、正しく置換でき有ません。

  • Windows2000 バッチファイルコマンドについて

    こんにちは。 バッチファイルコマンド(DOSコマンド?)について質問があります。 まずやりたい事としては、 「前月日付のフォルダを自動作成したい」 です。 当月日付をもってくる為には以下の様なコマンドでできました。 for /f "tokens=1-2" %%l in ('date /t') do set today=%%l for /f "delims=/ tokens=1-2" %%a in ('echo %today%') do set yymm=%%a%%b このコマンドを実行すると、例えば、%yymm%には200507が入っています。 このコマンドを応用して、前月日付(200506)を取得したいのですが、何か言い方法はありませんでしょうか? また、新たなやり方あるのでしたら教えて頂けないでしょうか?

専門家に質問してみよう