командная строка в Windows – минное поле

Отправлено 11 янв. 2016 г., 8:11 пользователем Anton Derbenev   [ обновлено 2 апр. 2016 г., 12:37 ]
У меня есть подозрение, что в недрах Microsoft есть специальная команда разработчиков, которая специально заботится, чтобы у всего, что связано с командной строкой Windows, были грабли, подводные камни и проблемы.

Примеры:
  1. %comspec% (cmd.exe) требует, чтобы все параметры после /C или /K были в кавычках. Наример, нельзя выполнить
     
    cmd.exe /C "%ProgramFiles%\notepad2\notepad2.exe" "%USERPROFILE%\Documents\test.txt"
    , надо
    cmd.exe /C ""%ProgramFiles%\notepad2\notepad2.exe" "%USERPROFILE%\Documents\test.txt""
    Что ещё хуже – cmd.exe маскирует этот косяк, и там, где "замечает" свой вызов, сам подставляет внешние кавычки (причём не всегда угадывает). Но остальные программы про это не в курсе! Например, это очень сильно мешает при использовании планировщика Windows.
  2. START "notepad.exe" – не работает. Работает 
    START "" "notepad.exe"
  3. "%windir%\System32\find.exe" /n "4" "test.txt" отдельно – работает.
    FOR /F "usebackq tokens=*" %%A IN (`"%windir%\System32\find.exe" /n "4" "test.txt"`) DO ECHO %%A – не работает. Работает
    FOR /F "usebackq tokens=*" %%A IN (`%windir%\System32\find.exe /n "4" "test.txt"`) DO ECHO %%A
  4. ECHO 123>test.txt – не работает.
    ECHO "123">test.txt – записывает "123" с кавычками.
    ECHO 123 >test.txt – с пробелом.
    Чтобы заработало без пробела, надо писать
    ECHO 12^3>test.txt
    или
    (ECHO 123)>test.txt
  5. ECHO – выводит ECHO is on.  или локализованную фразу (по русски – четыре длинных слова). Чтобы вывести пустую строку, надо писать
    ECHO.
    (с точкой слитно; также работает ECHO\, ECHO] и т.п.)
  6. Если внутри блока () будет комментарий со скобками, например, rem (проверка) , интерпретатор командной строки прочтёт закрывающую скобку как конец блока.
  7. FOR %%A in ("C:\test.file") DO ECHO %%A выводит C:\test.file независимо от наличия там test.file.
  8. Некоторые команды не меняют код ошибки ERRORLEVEL при вызове с неправильными параметрами командной строки. Самые назойливые примеры:
    1. NET SHARE (при этом NET USER – меняет)
    2. defrag.exe (на Win8 и выше его стоит запускать с ключом /O, на 7 этот ключ не поддерживается)
  9. До Windows Vista не было предустановленной переменной среды, в которой было бы указано расположение %USERPROFILE%\Local Settings\Application Data. В Vista добавили %LOCALAPPDATA%, но ещё добавили папку %USERPROFILE%\AppData\LocalLow, расположение которой снова не указано ни в какой переменной среды.
  10. Узнать hostname – нетривиальная задача. Есть переменная %COMPUTERNAME%, но там всегда в верхнем регистре и обрезано, если для NetBIOS оно "слишком длинное". Впрочем, его можно прочитать из реестра, только…
  11. При чтении ключей с помощью reg.exe проблемы начинаются, если в названии ключа есть пробелы, поскольку reg.exe никогда не выводит на экран только значение – оно выводится всегда после названия ключа и типа значения. Так что, чтобы, например, прочитать hostname, надо писать
    FOR /F "usebackq tokens=2*" %%I IN (`REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" /v "Hostname"`) DO SET "Hostname=%%~J"
    но чтобы прочитать NV Hostname, надо писать уже
    FOR /F "usebackq tokens=3*" %%I IN (`REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" /v "NV Hostname"`) DO SET "NVHostname=%%~J"
    Интересно, что reg.exe был уже в XP (в NT4 и 2000 он был в Resource Kit). Но XP'шная команда в выводе REG QUERY разделяет поля tab'ом (символ с кодом 8). Поскольку в названиях ключей tab'ов не бывает, такой вывод намного проще парсить (однако, от шапки всё равно никак не избавиться). Примерно так:
    FOR /F "usebackq tokens=2* delims=<tab>" %%I IN (`REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" /v "Hostname"`) DO SET "Hostname=%%~J"
    указанный жирным курсивом 
    <tab> должен быть в тексте пакетного файла в виде одного символа с кодом 8, а не в виде треугольных скобок и букв. В таком случае число после tokens= не зависит от количества пробелов в названии ключа.
    Кстати, если читаете путь из реестра, молитесь, чтобы там не было международных символов. Обнаружить их в командной строке – нереально, а выдаются reg'ом они в кодировке ANSI (напоминаю, cmd.exe работает в OEM), поэтому при наличии не-ASCII символов, при попытке совершить chdir (или что угодно другое) пакетный файл будет поджидать облом.
  12. Копирование папок – эпичный пример фейла (или win'а команды из первого абзаца?). Типичная команда для копирования папки в Windows:
    xcopy s:\WindowsImageBackup r:\WindowsImageBackup /E /I /Q /G /H /R /K /O /Y /B /J
    смогли с первого раза посчитать количество ключей? Ну ок, наверное, не все они требуются. Вот необходимый минимум, чтобы xcopy не остановился где-нибудь посередине и не задал тупой вопрос, ожидая интерактивного ответа: /E /I /G /H /R /Y. Да, кстати, Вы использовали copy? Облом будет поджидать Вас незаметно :) Ключи copy указываются перед аргументами откуда и куда, xcopy – после аргументов.
Comments