Запуск sqlcmd в пакетном файле работает, но работает тот же пакетный файл, что и запланированная задача, и ничего не делает - PullRequest
1 голос
/ 24 сентября 2019

Я посмотрел на многие SO вопросы / ответы, и, хотя некоторые из них кажутся похожими на мою проблему, они не кажутся.Ответы на данные вопросы исправляют вопросы, о которых спрашивали, но не решают мою проблему.

У меня есть командный файл ...

@ECHO ON

ECHO Disabling the following... >> C:\App\Debug.log
ECHO - V1 >> C:\Apps\Debug.log

FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'"`) DO (
        Echo %%F >> C:\Apps\Debug.log
)
EXIT /B

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

  1. Да, я убедился, что имя пользователя (с использованием whoami) одинаково для набора запланированных задачкак ручной запуск, который я выполняю.
  2. Да, я знаю, что пользователь, выполняющий сценарий, имеет права на все (как на доступ к файлам, так и на доступ к БД), потому что он отлично работает при запуске из командной строки.
  3. Запланированное задание настроено на выполнение, когда пользователь вошел в систему или нет.

Есть идеи, что может быть не так или что я могу попробовать в целях отладки?Спасибо!

1 Ответ

1 голос
/ 24 сентября 2019

sqlcmd возможно недостаточно.cmd.exe в среде запланированной задачи может не найти исполняемый файл, используя local PATHEXT и local PATH переменные среды.Исполняемый файл должен быть указан с полным именем файла, то есть диск + путь + имя + расширение.Тогда пакетный файл больше не зависит от переменных среды PATH и PATHEXT, поскольку на все файлы ссылаются с полным именем файла.

for выполняет указанную командную строку с запуском в фоновом режимедополнительный командный процесс с %ComSpec% /c и указанной командной строкой.Это означает, что выполняется с Windows, установленной на диске C::

C:\Windows\System32\cmd.exe /c sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'"

for захватывает все, что записано для обработки STDOUT запущенного командного процесса.Строки захваченного вывода обрабатываются построчно на for после того, как запуск cmd.exe завершается сам.Сообщения об ошибках, выводимые запущенным cmd.exe или командами / исполняемыми файлами, выполняемыми командным процессором Windows в фоновом режиме для обработки STDERR , перенаправляются для обработки STDERR командного процесса, обрабатывающего пакетный файл, и печатаются вприставка.Но при запуске командного файла в качестве запланированной задачи окно консоли отсутствует.Таким образом, сообщения об ошибках в этом случае не видны.

Командную строку for можно легко изменить здесь, чтобы получать также сообщения об ошибках, записанные в C:\Apps\Debug.log.

FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1' 2^>^&1"`) DO (

Microsoftстатья Использование операторов перенаправления команд поясняет 2>&1.Два оператора > и & должны быть экранированы с помощью ^, чтобы интерпретироваться как литеральные символы на командном процессоре Windows, анализирующем командную строку for перед выполнением finally for, которое выполняется следующим %ComSpec% /c с указанной командойстрока, в которой 2^>^&1 уже изменена на 2>&1.

Содержит ли файл журнала C:\App\Debug.log с этой модификацией следующие две строки?

'sqlcmd' не распознанв качестве внутренней или внешней команды,
работоспособная программа или командный файл.

Да, тогда запускаемый cmd.exe не найдет исполняемый файл с именем файла sqlcmd.Лучшее решение - ссылаться на этот исполняемый файл с полным именем файла.См. Также: По какой причине «X не распознается как внутренняя или внешняя команда, работающая программа или пакетный файл»?

В противном случае sqlcmd может выдать сообщение об ошибке, которое должнотеперь также в файле журнала C:\App\Debug.log.

Можно также использовать следующую командную строку, чтобы фон cmd.exe записывал сообщения об ошибках в отдельный файл журнала ошибок C:\App\Error.log:

FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'" 2^>C:\App\Error.log`) DO (

"tokens=* usebackq" приводит к тому, что сначала удаляются все начальные горизонтальные табуляции и обычные пробелы в непустых строках с помощью for, а затем проверяется, начинается ли оставшаяся строка с ;, в этом случае строка также игнорируется инаконец, присваиваемую захваченную строку не начиная с ; и удаляя начальные символы табуляции / пробелы для переменной цикла F для дальнейшей обработки.

Лучше было бы использовать параметры usebackq^ delims^=^ eol^=, не заключенные в двойные кавычки, что требуетэкранирование двух пробелов и двух знаков равенства с символом вставки ^ для интерпретации буквальных символов как cmd.exe on разбирает командную строку перед выполнением for.Режим разделения строк отключен, завершается с delims= из-за определения пустого списка разделителей.И никакая строка, за исключением пустой строки, больше не игнорируется, поскольку символ конца строки изменен со значения по умолчанию ; на отсутствие символа.

Наконец, пробел в строке echo, оставленный оператору перенаправления >>, также выводится echo и по этой причине записывается как конечный пробел в файл журнала.Поэтому при печати строки с echo, перенаправленной в файл, не должно быть свободного места до > или >>.Но нужно позаботиться об исключении пробела, оставленного оператору перенаправления. слово , оставленное оператору перенаправления, не должно быть 1, 2, ..., 9, так как это приведет к перенаправлению вывода на эти пронумерованные дескрипторы в указанный файл вместо символа1, 2 и т. Д. Поэтому, если неизвестный текст должен быть записан в файл, лучше сначала указать оператор перенаправления > или >> и полное имя файла, а затем команду echoс текстом для вывода.См. Также: Почему команда ECHO выводит в файл дополнительное конечное пространство?

Три командные строки с echo будут для этого пакетного файла:

ECHO Disabling the following...>> C:\App\Debug.log
ECHO - V1>> C:\Apps\Debug.log

>>C:\Apps\Debug.log ECHO %%F

following... безопасен для правильной записи в файл, также как V1.%%F может быть просто 1 или строкой, заканчивающейся пробелом и одной цифрой, поэтому лучше указывать перенаправление сначала в последней командной строке echo, чтобы окончательно выполнить cmd.exe командной строкой ECHO %%F 1>>C:\Apps\Debug.log.

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