Как вызвать popen () с путем, содержащим пробелы под Windows в C / C ++? - PullRequest
6 голосов
/ 13 октября 2009

Я пытаюсь вызвать popen (), используя mingw так:

#define RUN_COMMAND "\"C:\\Program Files\\CA\\BrightStor ARCserve Backup\\ca_qmgr.exe\" \"-list\""
int main() {
    outputPointer = popen(RUN_COMMAND, "r");
    ...
}

Но я не могу заставить его работать. Я думаю, что это кошмар цитирования ...

Ответы [ 5 ]

6 голосов
/ 06 мая 2017

Это решение было вдохновлено ответом от Kaz

Оказывается, функция popen удаляет кавычки вокруг всего, например. "C:/Program Files" становится C:/Program Files, а "Ab cd.exe" "ef gh" становится ab cd" "ef gh. Вы можете обойти это, просто добавив кавычки вокруг всего этого, например. ""ab cd.exe" "ef gh"", который становится "ab cd.exe" "ef gh", как и предполагалось.

4 голосов
/ 13 октября 2009

Взгляните на Что эквивалентно posix popen в api win32 . Я отказался от попытки использовать _popen() под Windows давным-давно. Чистое решение WIN32 работает намного надежнее.

Если mingw передает ваши параметры в sh -c вместо cmd.exe /c, то вы, вероятно, захотите изменить эти обратные слэши на прямые косые черты. Что-то вроде следующего должно помочь.

"\"C:/Program Files/CA/BrightStor ARCserve Backup/ca_qmgr.exe\" -list"
4 голосов
/ 16 апреля 2015

Эта проблема оказывается разрешимой. (Хотя, как и в большинстве случаев в Windows, не на 100%).

Функция popen открывает системную команду, что означает, что она почти наверняка просто принимает строковый аргумент и интерполирует его в cmd.exe /c <here>.

После некоторых интерактивных экспериментов с cmd.exe /c в командной строке Windows мы нашли способ запустить программу, в имени которой есть пробелы.

Наивная попытка с кавычками, нет:

C:\>cmd /c "foo bar"
'foo' is not recognized as an internal or external command,
operable program or batch file.

Можем ли мы избежать кавычек с помощью обхода?

C:\>cmd /c ^"foo bar^"
'foo' is not recognized [...]

Как насчет пространства?

C:\>cmd /c foo^ bar
'foo' is not recognized [...]

Как насчет цитирования только пробела?

C:\>cmd /c foo" "bar
'foo" "bar' is not recognized as an internal or external command,
operable program or batch file.

Aha! Это многообещающе! Это на самом деле пытается запустить foo bar? Посмотрим:

C:\>copy con "foo bar.bat"
echo i am foo bar
^Z
        1 file(s) copied.

C:\>cmd /c foo" "bar

C:\>echo i am foo bar
i am foo bar

Aha! Наш пакетный файл с пробелом в имени был запущен!

Итак, теперь я пытаюсь сделать следующее в Visual Studio 2008:

#include <stdio.h>

int main()
{
    FILE *in = _popen("C:\\Program\" \"Files\\Internet\" \"Explorer\\iexplore.exe", "r");

    if (in) {
        char line[200];
        printf("successfully opened!\n");
        if (fgets(line, 200, in))
            fputs(line, stdout);
        _pclose(in);
    }

    return 0;
}

Он отлично запускает Internet Explorer, затем блокирует fgets до тех пор, пока вы не выйдете из браузера (и не может ничего прочитать, так как нет вывода).

Он работает в MinGW, в котором используется библиотека времени выполнения Microsoft C; на самом деле, я предложил это решение, чтобы исправить ошибку в библиотеке языка программирования, который перенесен в Windows с использованием MinGW.

Предостережения:

Эта уловка не ускользнет от ведущих пробелов. Кажется, это работает для конечных пробелов. Ни то, ни другое не является проблемой; мы не часто видим имена путей, которые начинаются или заканчиваются пробелами, не говоря уже об именах исполняемых путей.

Я также не могу найти способ избежать встроенных двойных кавычек, которые могут встречаться как часть пути, и в то же время обрабатывать пробелы. Люди, вероятно, должны дважды подумать, прежде чем создавать что-то вроде C:\Program Files\Bob's so-called "editor"\bedit.exe.

1 голос
/ 27 декабря 2016

Я только что столкнулся с этой проблемой и безуспешно пытался решить проблему Каз. Я решил, что это просто изменить каталог, выполнить _popen без пути к исполняемому файлу, а затем вернуться в исходный каталог.

char cwd[MAX_PATH];
_getcwd(cwd, MAX_PATH);

if (_chdir("C:\\Program Files\\CA\\BrightStor ARCserve Backup") >= 0)
{
    outputPointer = _popen("ca_qmgr.exe \"-list\"", "r");
    _chdir(cwd);
}
0 голосов
/ 13 октября 2009

Согласно справочной странице для popen:

Аргументом команды является указатель на строка с нулевым символом в конце, содержащая командная строка оболочки. Эта команда передается в / bin / sh с помощью флага -c; интерпретация, если таковая имеется, в исполнении снаряда.

Итак, вы хотите экранировать строку для sh для анализа. Вам не нужно экранировать аргумент -list, и вы можете попробовать экранировать пробелы вместо того, чтобы заключать в кавычки полное имя программы. У меня нет системы Windows для тестирования, но я бы предложил

#define RUN_COMMAND "C:\\Program Files\\CA\\BrightStor\\ ARCserve\\ Backup\\ca_qmgr.exe -list"
int main() {
    outputPointer = popen(RUN_COMMAND, "r");
    ...
}
...