質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.52%

batファイル内で、スペースを含む引数をCプログラムに渡す場合の処理

受付中

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 3,866

minato_hy

score 40

前提・実現したいこと

受け取ったコマンドライン引数を列挙するCプログラムがあり、batファイル内でそのCプログラムに引数を渡し実行したいのですが、引数にスペースが含まれる場合の処理に困っています。

発生している問題・エラーメッセージ

[1] スペースを含むパスを変数に格納し、Cプログラムにその変数を引数として渡した場合、そのまま渡すとスペースの部分で変数の中身が分割されてしまいます。

[2] しかし変数を渡すときにダブルクォーテーションで囲むと、なぜかその変数以降の引数まで合わせてひとつの引数と認識されてしまいます。

なにか解決方法はありますでしょうか。

[1]の場合の結果
0: a
1: C:\test
2: files\
3: 2
4: 3

[2]の場合の結果
0: a
1: C:\test files\ 2 3

該当のソースコード

batファイルの場所:C:\test files\

a.exe

#include<stdio.h>
int main(int argc, char *argv[]){
    int i;
    for(i=0; i<argc; i++){
        printf("%d: %s\n", i, argv[i]);
    }
    return 0;
}

test.bat

@echo off
rem 
set path=%~dp0          // カレントディレクトリのパス(スペースが含まれる)
a.exe %path% 2 3     // [1]の場合
a.exe "%path%" 2 3 // [2]の場合

補足情報(言語/FW/ツール等のバージョンなど)

windows7
gcc

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+2

2つ目の"が、直前に\があるためにエスケープされた状態になっています。
\\と重ねると、gccだと上手く行きます。bccは駄目ですね。Cに依存するようです。

あと、PATHという環境変数名は特別な意味を持っていますので、他の目的には使わない方が良いです。

set A=%~dp0
a.exe "%A%\" 2 3

追記

上記で駄目な場合、
案1.%A%の後に何か文字(空白とか)を付け加えてプログラムに渡し、プログラムでそれを取り除く
案2.%A%の末尾の\を取り除いてからプログらに渡し、プログラムで\を付加する
くらいでしょうか。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/21 20:36

    なるほど、変数内の末尾の \ は気付きませんでした。gccで試してみたところ末尾に余計な \ が付いてしまいますが、Cプログラム側の処理でなんとかなりそうです。
    なおPATHについては説明の解りやすさのために投稿時のみこの変数名にしております。とはいえご忠告感謝です。

    キャンセル

  • 2017/06/21 23:45

    > 投稿時のみこの変数名にしております
    であれば、PATHNAMEとかが良かったですね。

    キャンセル

+1

otnさんのコメントから「WindowsではexecutableのCランタイムにより引数の解釈が変わる」という点がようやく実感できた気がします。以下の回答の前提はcygwin64上のgcc 6.3.0で作成したexecutableです。あまり一般的とはいえないかもですね。

to:質問者さん
どのコンパイラー(どのCランタイム)かにより違うということだと思います。それを明確にしたほうがよさそうですね。


set path=%~dp          // カレントディレクトリのパス(スペースが含まれる)

バッチファイルに%~dpと書いてやってみたのですがパス演算子が間違って使われてますというエラーになり、どうやったらこの記述が動くのか自分にはわかりませんでした。そこでバッチファイルが存在するディレクトリーなのだろうと解釈し%~dp0に置き換えてやってみました。(Windows10 64bit)

で、内容がバックスラッシュで終わっている変数を一つの引数として渡す場合、ダブルクォート文字ではなくシングルクォート文字で囲むといいみたいです。

a.exe '%変数名%' arg2 arg3 ...

ただotnさんのコメントを拝見すると、この方法が正しいかどうか少々自身ないです。コンパイラーのランタイムによってコマンドの引数の解釈が変わってくる(!)ということがどういう理屈か自分に分かっていないからです。自分はcygwin64のgccでa.exeを作成し、それをコマンドプロンプト上で動かすという少々ヘンテコなことをしています。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/21 17:12

    私は、mingw の gcc ですが、cygwinとは仕様が違うようですね。mingwだとシングルクォートは特殊文字じゃ無いようです。

    キャンセル

  • 2017/06/21 17:38 編集

    自分は知らず知らずのうちにargc, argvを決める引数の分離がWindowsでも呼び出し側で決まるというふうに思い込んでいました。CreateProcessのリファレンスをみたら「引数を並べた単一の文字列が第二引数になっているだけ」ということに今更ながら気づいて愕然としました・・・
    Win32 APIを使ったことがないとはいえ、ちょっと恥ずかしい勘違いです。
    otnさんの回答とコメントで勉強させていただきました。大変ありがとうございました。

    キャンセル

  • 2017/06/21 20:47

    私もcygwin上のgccでコンパイルしコマンドプロンプト上で実行するので、シングルクォーテーションで上手くいきそうです。色々検索してもシングルクォーテーションについては調べられなかったので助かりました。後ほど試してみて、成功すればいったんこの質問は閉じさせていただきます。

    キャンセル

  • 2017/06/21 20:49

    あとコメントに入れ忘れましたが%~dpはご指摘の通りバッチファイルのディレクトリを取得する%~dp0のミスです。質問文修正しました。

    キャンセル

0

うまくいくかわかりませんが、スペースを含むひとかたまりの値をシングルクォーテーションでくくっておいて、それらをダブルクォーテーションでくくって渡してあげたらどうなりますか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/21 20:39

    "'%PATH%'"で試してみると、'C:\test files\'とシングルクォーテーションで囲まれてはいましたがちゃんと引数ごとに表示されていました。ちなみに、'"%PATH%"'というように内側をダブルクォーテーションにしたところ、"C:\test files\"のように表示されました。なるほど

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.52%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる