Как предотвратить вставку командой Rust std :: process: Command относительного пути .exe в аргументы? - PullRequest
0 голосов
/ 12 января 2019

Я использую std:process:Command Rust для вызова robocopy в Windows. К сожалению, кажется, что где-то при выполнении robocopy относительный путь из .exe вставляется перед каждым каталогом.

Кроме того, простые вызовы, такие как net use, работают с одним и тем же методом, хотя я тестировал только те, которые не зависят ни от каких каталогов.

Редактировать: обновлены тестовые папки, чтобы в их именах были пробелы.

Редактировать 2: код был обновлен вместе с решением. Решение состояло в том, чтобы вызвать robocopy напрямую и .arg() во всем индивидуально. Старые попытки до сих пор комментируются.

Вместо отправки

cmd.exe /c robocopy "C:\Test\Test 1" "C:\Test\Test 2" /MIR /copy:DAT /MT:32 /Z /R:2 /W:03 /v /LOG:"C:\Test\Test 3\logfile.log"

и он успешно работает, вывод содержит много ошибок:

ERROR 123 (0x0000007B) Opening Log File C:\relative\path\where\exe\is\located\"C:\Test\Test 3\logfile.log"
The filename, directory name, or volume label syntax is incorrect.

-------------------------------------------------------------------------------
   ROBOCOPY     ::     Robust File Copy for Windows
-------------------------------------------------------------------------------

   Started : Tuesday, January 8, 2019 7:35:41 AM
    Source - C:\relative\path\where\exe\is\located\"C:\Test\Test 1"\
      Dest - C:\relative\path\where\exe\is\located\"C:\Test\Test 2"\

     Files :
   Options : /V /S /E /DCOPY:DA /COPY:DAT /PURGE /MIR /Z /MT:32 /R:2 /W:3

------------------------------------------------------------------------------

ERROR : Invalid Parameter #10 : "/LOG:"C:\Test\Test 3\logfile.log""

Эта проблема возникает с помощью:

  • Ржавчина версия 1.3.1

  • Windows 10

Код, который вызывает это для меня, показан ниже. Чтобы использовать его, вам нужно поместить папку Test в C: \ (или изменить ее на другое место) и поместить в этот каталог Test 1 папка с некоторыми Testfile.txt , чтобы помочь показать, что копирование имело место, а также папка Test 3 для журнала, чтобы быть в нем (не уверен, что журнал может создать свою собственную папку - так что, чтобы быть в безопасности, заранее приготовьте его!). В основном вы хотите:

C:\Test\Test 1\Testfile.txt (name or type of file doesn't matter)
C:\Test\Test 3\

robocopy должен запуститься и создать папку C: \ Test \ Test 2 с Testfile.txt и поместить в нее logfile.log C: \ Test \ Test 3 , которая детализирует транзакцию. В конце каталоги должны выглядеть так:

C:\Test\Test 1\Testfile.txt
C:\Test\Test 2\Testfile.txt
C:\Test\Test 3\logfile.log

Код следует:

//-----Import Built-in Libraries (not called crates)-----
use std::process::Command; //use cmd.exe

fn main()
{
    let commandOpt1 = "/MIR"; //mirror directories
    let commandOpt2 = "/copy:DAT"; //copy attributes
    let commandOpt3 = "/MT:32"; //use 32 I/O threads (low CPU still, but better bandwidth utilization)
    let commandOpt4 = "/Z"; //idr
    let commandOpt5 = "/R:2"; //Retry twice
    let commandOpt6 = "/W:03"; //Wait 3 sec between tries
    let commandOpt7 = "/v"; //verbose logging
    let commandLogStr = "/LOG:\"C:\\Test\\Test 3\\logfile.log\""; //record where the log file goes
    let commandLogNoParenthStr = "/LOG:C:\\Test\\Test 3\\logfile.log"; //record where the log file goes
    let command = format!("robocopy \"C:\\Test\\Test 1\" \"C:\\Test\\Test 2\" {} {} {} {} {} {} {} {}",
    commandOpt1,commandOpt2,commandOpt3,commandOpt4,commandOpt5,commandOpt6,
    commandOpt7,commandLogStr); //build the command
    let commandStr: &str = &*command; //these two types of strings are
    println!("TEST-Command for robocopy:{}",command);

    //let m = Command::new("cmd.exe").arg("/c").arg(commandStr).output().unwrap(); //run cmd.exe net use
    /*let m = Command::new("cmd.exe")
        .arg("/c")
        .arg("robocopy")
        .arg("\"C:\\Test\\Test 1\"")
        .arg("\"C:\\Test\\Test 2\"")
        .arg(commandOpt1)
        .arg(commandOpt2)
        .arg(commandOpt3)
        .arg(commandOpt4)
        .arg(commandOpt5)
        .arg(commandOpt6)
        .arg(commandOpt7)
        .arg(commandLogStr)
        .output().unwrap(); //run cmd.exe net use */
    let m = Command::new("robocopy")
        .arg("C:\\Test\\Test 1")
        .arg("C:\\Test\\Test 2")
        .arg(commandOpt1)
        .arg(commandOpt2)
        .arg(commandOpt3)
        .arg(commandOpt4)
        .arg(commandOpt5)
        .arg(commandOpt6)
        .arg(commandOpt7)
        .arg(commandLogNoParenthStr )
        .output().unwrap(); //run cmd.exe net use */
    let mOutput = String::from_utf8_lossy(&m.stdout); //get the output
    println!("TEST-cmd output: {}",mOutput);
    println!("TEST-cmd status: {}", m.status.success()); //reports success (true or false) of command
    println!("TEST-cmd stderr: {}", String::from_utf8_lossy(&m.stderr)); //reports error words of command
    let _ = Command::new("cmd.exe").arg("/c").arg("pause").status(); // wait for user input
}

Код дает две опции: одну для вызова robocopy в одном добавлении .arg() и одну с разбивкой .arg(). Для меня они дают одинаковый результат - но варианты хороши!

Также, как примечание, я отправляю все в Command как &str, но это, кажется, не требуется - Strings также может быть .arg() с.

1 Ответ

0 голосов
/ 12 января 2019

У меня нет машины с Windows, но я уверен, что проблема в кавычках ".

Правила выхода из CMD.exe довольно странные: иногда вам нужны кавычки, иногда нет, а иногда вы не должны их использовать.

В вашем случае, например, файл журнала выбирается со следующей опцией (удаление Rust Escapes): /LOG:"C:\Test\Test3\logfile.log". Это имя файла, которое начинается и заканчивается кавычкой. И поскольку он не начинается с буквы диска или \, ОС думает: конечно, это относительный путь, давайте посмотрим на C:\...\"C:\Test..."!

Решение простое: просто удалите все эти цитаты.

Чего я не понимаю, так это почему вы звоните cmd.exe /c вместо того, чтобы просто звонить robocopy напрямую. Кавычки в командной строке используются для управления анализатором командной строки и правильного управления именами файлов с пробелами и так далее. Но если вы делаете Command::new() из robocopy напрямую, тогда нет необходимости заключать в кавычки, потому что аргументы уже переданы отдельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...