質問
私は、std::stringを含むコマンドを実行するとexecv、最高の"C++"に変換する"char*argv[]"を要求された場合のパラメータのexecv()?
の解明:
std::string cmd = "mycommand arg1 arg2";
char *cmd_argv[];
StrToArgv(cmd, cmd_argv); // how do I write this function?
execv(cmd_argv[0], cmd_argv);
解決
std::vector<char *> args;
std::istringstream iss(cmd);
std::string token;
while(iss >> token) {
char *arg = new char[token.size() + 1];
copy(token.begin(), token.end(), arg);
arg[token.size()] = '\0';
args.push_back(arg);
}
args.push_back(0);
// now exec with &args[0], and then:
for(size_t i = 0; i < args.size(); i++)
delete[] args[i];
もちろん、これはrm "a file.mp3"
のように引用符を使用commansでは動作しません。あなたはそれとはるかに気POSIX関数wordexp
を考慮することができます。
他のヒント
ここでは非常に非unixyの答え。何が問題になっています:
std::string cmd = "echo hello world";
execl("/bin/sh", "/bin/sh", "-c", cmd.c_str(), NULL);
完璧に良いものがシステムにすでにありますのに、なぜコマンドラインパーサを書いてわざわざ?
(注意:あなたが実行しようとしている文字列を信用していないので、一つの良い理由がある一つは、これはすでに真実であることを期待しているが、シェルはその文字列で、「もっと」を行いますナイーブ空白スプリッタより。あなたが注意されていない場合、したがって、より多くのセキュリティホールを開きます。)
をスペースでそれを分割するc_str()文字列の方法とはstrtokの組み合わせは、()あなたが(EXECに渡す必要がある文字列の配列)およびその関連機能を取得する必要があります。
Boost.ProgramOptionsから多分split_winmain
。ブーストは、ほとんどの場合に適しています。
http://www.boost.org/ DOC / libsに/ 1_40_0 / DOC / HTML / program_options / howto.html#id1396212する
、あなたはMS Cランタイムと同じ規則を使用していますAPI関数CommandLineToArgvW
を使用することができます。
一般的には、プラットフォームおよび/またはシェルの引用スタイルに依存します。マイクロソフトCランタイムは、例えばよりも全く異なるスタイルを使用していますbashの!
OK、私は自分自身に十分な時間、この上でつまずくしてきました。これは、「C」ストレートなので、CまたはC ++のいずれかに接続することができます。それは異なったシングルと二重引用符文字列を扱います。呼び出し側はARGVを解放する責任がある[0](そうでない場合はNULL)およびargv
#include
#include
#include
#include
typedef enum {
STR2AV_OK = 0,
STR2AV_UNBALANCED_QUOTE
} str_to_argv_err_t;
#ifndef NUL
#define NUL '\0'
#endif
static char const nomem[] = "no memory for %d byte allocation\n";
static str_to_argv_err_t
copy_raw_string(char ** dest_p, char ** src_p);
static str_to_argv_err_t
copy_cooked_string(char ** dest_p, char ** src_p);
static inline void *
Xmalloc(size_t sz)
{
void * res = malloc(sz);
if (res == NULL) {
fprintf(stderr, nomem, sz);
exit(EXIT_FAILURE);
}
return res;
}
static inline void *
Xrealloc(void * ptr, size_t sz)
{
void * res = realloc(ptr, sz);
if (res == NULL) {
fprintf(stderr, nomem, sz);
exit(EXIT_FAILURE);
}
return res;
}
str_to_argv_err_t
string_to_argv(char const * str, int * argc_p, char *** argv_p)
{
int argc = 0;
int act = 10;
char ** res = Xmalloc(sizeof(char *) * 10);
char ** argv = res;
char * scan;
char * dest;
str_to_argv_err_t err;
while (isspace((unsigned char)*str)) str++;
str = scan = strdup(str);
for (;;) {
while (isspace((unsigned char)*scan)) scan++;
if (*scan == NUL)
break;
if (++argc >= act) {
act += act / 2;
res = Xrealloc(res, act * sizeof(char *));
argv = res + (argc - 1);
}
*(argv++) = dest = scan;
for (;;) {
char ch = *(scan++);
switch (ch) {
case NUL:
goto done;
case '\\':
if ( (*(dest++) = *(scan++)) == NUL)
goto done;
break;
case '\'':
err = copy_raw_string(&dest, &scan);
if (err != STR2AV_OK)
goto error_leave;
break;
case '"':
err = copy_cooked_string(&dest, &scan);
if (err != STR2AV_OK)
goto error_leave;
break;
case ' ':
case '\t':
case '\n':
case '\f':
case '\r':
case '\v':
case '\b':
goto token_done;
default:
*(dest++) = ch;
}
}
token_done:
*dest = NUL;
}
done:
*argv_p = res;
*argc_p = argc;
*argv = NULL;
if (argc == 0)
free((void *)str);
return STR2AV_OK;
error_leave:
free(res);
free((void *)str);
return err;
}
static str_to_argv_err_t
copy_raw_string(char ** dest_p, char ** src_p)
{
for (;;) {
char ch = *((*src_p)++);
switch (ch) {
case NUL: return STR2AV_UNBALANCED_QUOTE;
case '\'':
*(*dest_p) = NUL;
return STR2AV_OK;
case '\\':
ch = *((*src_p)++);
switch (ch) {
case NUL:
return STR2AV_UNBALANCED_QUOTE;
default:
/*
* unknown/invalid escape. Copy escape character.
*/
*((*dest_p)++) = '\\';
break;
case '\\':
case '\'':
break;
}
/* FALLTHROUGH */
default:
*((*dest_p)++) = ch;
break;
}
}
}
static char
escape_convt(char ** src_p)
{
char ch = *((*src_p)++);
/*
* Escape character is always eaten. The next character is sometimes
* treated specially.
*/
switch (ch) {
case 'a': ch = '\a'; break;
case 'b': ch = '\b'; break;
case 't': ch = '\t'; break;
case 'n': ch = '\n'; break;
case 'v': ch = '\v'; break;
case 'f': ch = '\f'; break;
case 'r': ch = '\r'; break;
}
return ch;
}
static str_to_argv_err_t
copy_cooked_string(char ** dest_p, char ** src_p)
{
for (;;) {
char ch = *((*src_p)++);
switch (ch) {
case NUL: return STR2AV_UNBALANCED_QUOTE;
case '"':
*(*dest_p) = NUL;
return STR2AV_OK;
case '\\':
ch = escape_convt(src_p);
if (ch == NUL)
return STR2AV_UNBALANCED_QUOTE;
/* FALLTHROUGH */
default:
*((*dest_p)++) = ch;
break;
}
}
}
このバリエーションlitbの答えはずなので、すべてのマニュアルメモリの割り当て.それはまだな取扱い引用.
#include <vector>
#include <string>
#include <sstream>
std::string cmd = "mycommand arg1 arg2";
std::istringstream ss(cmd);
std::string arg;
std::list<std::string> ls;
std::vector<char*> v;
while (ss >> arg)
{
ls.push_back(arg);
v.push_back(const_cast<char*>(ls.back().c_str()));
}
v.push_back(0); // need terminating null pointer
execv(v[0], &v[0]);
感じるような汚れのconst_cast<>が、プログラムんなの内容を改変する行為のargvの文字列です。
あなたはchar *に変換することのstd ::文字列のc_str()関数を使用することができます。 strtok関数は、「」区切り文字を使用して文字列を分割します。
マット・Peitrekの LIBTINYC には、文字列を受け取り、それを解析しargcargv.cppと呼ばれるモジュールを持っていますアカウントに引用された引数を取る引数配列にアウト。それはWindows固有のだが、それはあなたが好きなプラットフォームへの移行が容易であるべき非常に簡単だということに注意してください。
あなたがそれを行う場合は、代わり外部宣言(アドバイスの私の少し)を使用してのargv配列に数とポインタを置くloactionをパラメータとして、それは取るように変更。マットは必要としなかったことLIBTINYCは、のだったので、のランタイムます。
また、あなたはあなたのコンパイラのランタイムソースで見ることができ、彼らは(それが実行可能であることが判明した場合)コマンドラインを解析して、直接それを呼び出すために何を見るために(ほぼすべてのそれを提供)またはそのビットからアイデアを借りますコードます。
この質問に答えるために遅すぎるかもしれないが、あなたはスタンダールPOSIX関数<のhref =「http://pubs.opengroup.org/onlinepubs/9699919799/functions/glob.html」のrel = "nofollowをを使用することができますnoreferrer」タイトル= "グロブ">グロブのか、のwordexp :
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <wordexp.h>
int
main(int argc, char **argv)
{
wordexp_t p;
char *exec_path = "/bin/ls";
p.we_offs = 1;
wordexp("-l -t /etc", &p, WRDE_DOOFFS);
p.we_wordv[ 0 ] = exec_path;
execv(exec_path, p.we_wordv);
/* This code is unreachable */
exit(EXIT_SUCCESS);
}
一覧表示、および-l
を実行するために-t
(ロングリスト形式)、/etc
(更新時刻でソート)とディレクトリ/bin/ls
:これは、3つのパラメータを準備します。コールwordexp()
はあなたにコール/bin/sh -c
が以前お奨めしかしspawanedプロセスは、親プロセスが/bin/sh
ないだろうとまったく同じ結果が得られます。
これは、機能を判明したように、このためのブーストプログラムオプションにやや隠れた存在。 split_unix()関数は、エスケープと引用されたコマンドラインで動作します。
#include "boost/program_options/parsers.hpp"
auto parts = boost::program_options::split_unix(commandLine);
std::vector<char*> cstrings ;
for(auto& str : parts){
cstrings.push_back(const_cast<char*> (str.c_str()));
}
int argc = (int)cstrings.size();
char** argv = cstrings.data();