문제

execv로 실행될 명령이 포함된 std::string이 있습니다. 이를 execv()의 두 번째 매개변수에 필요한 "char *argv[]"로 변환하는 가장 좋은 "C++" 방법은 무엇입니까?

명확히 하기 위해:

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". POSIX 기능을 고려할 수 있습니다 wordexp 그것에 관심을 갖는 것과 훨씬 더.

다른 팁

여기에서 매우 비 이사신 답변. 무엇이 문제가 있습니까 :

std::string cmd = "echo hello world";
execl("/bin/sh", "/bin/sh", "-c", cmd.c_str(), NULL);

이미 시스템에 완벽하게 좋은 것이있을 때 명령 줄 파서를 쓰는 이유는 무엇입니까?

(참고 : 한 가지 좋은 이유는 당신이 실행하려고하는 줄을 믿지 않기 때문입니다. 이것은 이미 사실이기를 희망하지만, 순진한 흰색 공백-스플리터보다 쉘이 그 문자열로 더 많이 할 것입니다. 조심하지 않으면 더 많은 보안 구멍을 엽니 다.)

c_str() 문자열 메서드와 strtok()를 조합하여 공백으로 분할하면 exec() 및 관련 함수에 전달해야 하는 문자열 배열을 얻을 수 있습니다.

아마도 split_winmain boost.programoptions에서. 부스트는 대부분의 경우 좋은 선택입니다.http://www.boost.org/doc/libs/1_40_0/doc/html/program_options/howto.html#id1396212

Windows에만 관심이있는 경우 (다른 커널은 일반적으로 Windows Sense의 명령 줄에 대해 알지 못함) API 기능을 사용할 수 있습니다. CommandLineToArgvW MS C 런타임과 동일한 규칙을 사용합니다.

일반적으로 플랫폼의 인용 스타일 및/또는 쉘에 따라 다릅니다. Microsoft C 런타임은 예를 들어 Bash와는 상당히 다른 스타일을 사용합니다!

좋아, 나는 이것을 충분히 스스로 넘어 뜨렸다. 이것은 직선 "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 문자열의 내용을 수정해서는 안됩니다.

std :: 문자열의 c_str () 함수를 사용하여 char*로 변환 할 수 있습니다. Strtok 함수는``Delimiter를 사용하여 문자열을 분할합니다.

Matt Peitrek 's libtinyc argcargv.cpp라는 모듈이 있으며 문자열을 가져 와서 인용 된 인수를 고려한 인수 배열에 구문 분석합니다. Windows 특정이지만 매우 간단하므로 원하는 플랫폼으로 쉽게 이동할 수 있어야합니다.

그렇게한다면, 매개 변수로 가져 오도록 변경하여 Loaction을 사용하여 외부를 사용하는 대신 ArgV 배열에 대한 포인터를 넣습니다 (약간의 조언 만). Matt는 libtinyc 때문에 그것을 필요로하지 않았습니다 ~였다 런타임.

또는 컴파일러의 런타임 소스를 살펴보면 (거의 모든 것이 제공) 명령 선을 구문 분석하고 직접 전화하거나 해당 코드에서 아이디어를 빌릴 수 있습니다.

이 질문에 대답하기에는 너무 늦었을 수도 있지만 standart posix 함수를 사용할 수 있습니다. 글로벌 또는 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);
}

3 개의 매개 변수를 준비합니다. -l (긴 목록 형식), -t (수정 시간별로 정렬) 및 디렉토리 /etc 나열하고 실행합니다 /bin/ls. 부르다 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();
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top