Почему в созданном из 1С bat-файле выполняется только первая строка?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Нередко разработчики сталкиваются с ситуацией, когда командный файл (.bat), сформированный программно в 1С, успешно и до конца отрабатывает при ручном клике пользователем, но при запуске из кода 1С (особенно в серверном контексте) застревает или прерывается: отрабатывает только первая команда, а последующие строки игнорируются. Разберем по шагам, почему возникает такое поведение, как правильно локализовать ошибку и какими способами надежно запускать внешние консольные утилиты.

Проанализируем исходную ситуацию. В коде 1С генерируется командный файл следующего содержания для пакетной обработки изображений:


montage C:\Test\2.jpg C:\Test\3.jpg -geometry 400x300 C:\Test\23.jpg
convert C:\Test\1.jpg -resize 1024x768 C:\Test\11.jpg
convert C:\Test\23.jpg -resize 1024x768 C:\Test\23.jpg
convert -append C:\Test\11.jpg C:\Test\23.jpg C:\Test\23.jpg

Для создания и запуска файла используется стандартная функция через Windows Script Host:


Функция ЗаписатьИВыполнитьБатник(КоманднаяСтрока, ПутьКБатнику)
    
    Текст = Новый ТекстовыйДокумент;
    Текст.УстановитьТекст(КоманднаяСтрока);
    Текст.Записать(ПутьКБатнику, "cp866");
    
    Попытка
        Объект = Новый COMОбъект("wscript.shell");
        Объект.Run(ПутьКБатнику, 0, Истина);
        Возврат Истина;
    Исключение
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ОписаниеОшибки());
        Возврат Ложь;
    КонецПопытки;
    
КонецФункции

При вызове на стороне сервера первая строка (montage) завершается, а вторая (convert) не дает ожидаемого результата, блокируя весь процесс.

Выясним причину проблемы: коллизия системных имен

Первая мысль разработчика — отсутствие прав на файлы или некорректная кодировка переноса строк. Однако истинная причина кроется в специфике поиска исполняемых файлов командным интерпретатором Windows в среде службы сервера 1С.

Команда convert — это не только утилита пакета ImageMagick, но и стандартная системная утилита Windows (C:\Windows\System32\convert.exe), предназначенная для преобразования файловых систем из FAT в NTFS. Когда скрипт запускается под интерактивным сеансом пользователя, пути в переменной среды PATH могут разрешаться в пользу установленного ПО. Однако служба сервера 1С (работающая в изоляции Session 0 под учетной записью USR1CV8) имеет свой набор переменных среды и текущий рабочий каталог (часто C:\Windows\System32).

В итоге интерпретатор вызывает не утилиту обработки изображений, а системную команду конвертации диска. Системная утилита ожидает подтверждения или параметров тома в потоке ввода stdin. Поскольку запуск происходит в скрытом режиме (параметр 0 в методе Run), консоль зависает в бесконечном ожидании пользовательского ввода, и управление никогда не переходит к следующим строкам скрипта.

Диагностика с помощью логирования

Чтобы убедиться, на какой именно команде спотыкается процесс и какую ошибку возвращает консоль, включим перенаправление вывода и ошибок в лог-файл. Модифицируем батник следующим образом:


echo Запуск montage >> C:\Test\log.txt 2>&1
montage C:\Test\2.jpg C:\Test\3.jpg -geometry 400x300 C:\Test\23.jpg >> C:\Test\log.txt 2>&1
echo Запуск convert >> C:\Test\log.txt 2>&1
convert C:\Test\1.jpg -resize 1024x768 C:\Test\11.jpg >> C:\Test\log.txt 2>&1

Конструкция 2>&1 перенаправляет поток ошибок в поток стандартного вывода. Открыв созданный log.txt, мы сразу увидим сообщение от системной утилиты Windows: «Преобразование файловой системы тома из FAT в NTFS...».

Решение 1. Использование полных путей к исполняемым файлам

Самый прямой и надежный способ исключить неоднозначность — указывать абсолютные пути к бинарным файлам утилит, обязательно заключая их в кавычки из-за возможных пробелов в имени директорий (например, Program Files).

При формировании батника текст команд должен выглядеть так:


"C:\Program Files\ImageMagick-7.0.5-Q16\montage.exe" C:\Test\2.jpg C:\Test\3.jpg -geometry 400x300 C:\Test\23.jpg
"C:\Program Files\ImageMagick-7.0.5-Q16\convert.exe" C:\Test\1.jpg -resize 1024x768 C:\Test\11.jpg
"C:\Program Files\ImageMagick-7.0.5-Q16\convert.exe" C:\Test\23.jpg -resize 1024x768 C:\Test\23.jpg
"C:\Program Files\ImageMagick-7.0.5-Q16\convert.exe" -append C:\Test\11.jpg C:\Test\23.jpg C:\Test\23.jpg

Решение 2. Смена рабочей директории в начале скрипта

Если скрипт уже сформирован и не хочется переписывать каждую строку, достаточно первой инструкцией батника сделать переход в каталог с целевыми программами с помощью команды cd /d (ключ /d нужен для корректной смены диска при необходимости):


cd /d "C:\Program Files\ImageMagick-7.0.5-Q16"
montage C:\Test\2.jpg C:\Test\3.jpg -geometry 400x300 C:\Test\23.jpg
convert C:\Test\1.jpg -resize 1024x768 C:\Test\11.jpg
convert C:\Test\23.jpg -resize 1024x768 C:\Test\23.jpg
convert -append C:\Test\11.jpg C:\Test\23.jpg C:\Test\23.jpg

Решение 3. Использование синтаксиса ImageMagick 7 (утилита magick)

Начиная с версии ImageMagick 7, разработчики пакета перешли на единую утилиту magick.exe, чтобы раз и навсегда исключить конфликт с системной утилитой Windows. Все вспомогательные команды теперь вызываются через нее:

  1. Вместо convert используется команда magick (или magick convert).
  2. Вместо montage используется magick montage.

Пример команды в батнике:


magick montage C:\Test\2.jpg C:\Test\3.jpg -geometry 400x300 C:\Test\23.jpg
magick C:\Test\1.jpg -resize 1024x768 C:\Test\11.jpg
magick C:\Test\23.jpg -resize 1024x768 C:\Test\23.jpg
magick -append C:\Test\11.jpg C:\Test\23.jpg C:\Test\23.jpg

Решение 4. Отказ от WScript.Shell в пользу ЗапуститьПриложение

Использование COM-объекта wscript.shell на сервере 1С несет в себе риски: создание COM-объектов может блокироваться профилями безопасности кластера 1С, а сам вызов менее управляем. Платформа 1С предоставляет штатный метод ЗапуститьПриложение, который умеет передавать рабочий каталог и возвращать код завершения программы.

Посмотрим на пример правильной организации вызова без создания промежуточных bat-файлов (или с запуском bat-файла штатно):


КодВозврата = 0;
СтрокаКоманды = "cmd.exe /c """ + ПутьКБатнику + """";
РабочийКаталог = "C:\Program Files\ImageMagick-7.0.5-Q16";

ЗапуститьПриложение(СтрокаКоманды, РабочийКаталог, Истина, КодВозврата);

Если КодВозврата <> 0 Тогда
    ВызватьИсключение "Ошибка выполнения скрипта, код возврата: " + Строка(КодВозврата);
КонецЕсли;

Передавая РабочийКаталог вторым параметром метода ЗапуститьПриложение, мы гарантируем, что среда исполнения запустится именно в папке сторонней утилиты, а параметр Истина обеспечит синхронное ожидание завершения работы процесса.

← На главную