Скрытые возможности пакетных файлов Windows

232

Каковы некоторые из менее известных, но важных и полезных функций пакетных файлов Windows?

Руководящие указания:

  • Одна особенность за ответ
  • Дайте краткое описание функции и пример , а не просто ссылку на документацию
  • Ограничение ответов на встроенную функциональность , т. Е. Не требует дополнительного программного обеспечения, такого как Windows Resource Kit

Пояснение: здесь мы ссылаемся на скрипты, которые обрабатываются cmd.exe, который является вариантом по умолчанию для вариантов WinNT.

(См. Также: Пакетные файлы Windows: .bat против .cmd? )

Крис Но
источник

Ответы:

185

Продолжение линии:

call C:\WINDOWS\system32\ntbackup.exe ^
    backup ^
    /V:yes ^
    /R:no ^
    /RS:no ^
    /HC:off ^
    /M normal ^
    /L:s ^
    @daily.bks ^
    /F daily.bkf
Chris Noe
источник
2
Я искал это на прошлой неделе! (не помнил персонажа)
Chilltemp
21
^ Действительно символ кавычки. Используя его, вы можете заключить в кавычки <и>, чтобы они не перенаправляли вывод. ^ В конце строки также позволяет продолжить строку.
Cheeso
Не могли бы вы объяснить этот маленький скриптлет?
guerda
2
@furtelwart: Это то же самое , как если бы вы написали все в одну строку: call C:\WINDOWS\system32\ntbackup.exe backup /V:yes /R:no /RS:no /HC:off /M normal /L:s @daily.bks /F daily.bkf. И чтобы понять все параметры этой линии, просто запустите C:\WINDOWS\system32\ntbackup.exe /?.
Курт Пфайфл
Глубокая дискуссия по этой теме: длинные команды разбиты на несколько строк
jeb
150
PUSHD path

Переходит в каталог , указанный путь .

POPD

Возвращает вас в каталог, из которого вы «нажали».

ворон
источник
5
Это также работает как полный стек, так что вы можете поместить много каталогов в стек, а затем продолжить работу, чтобы вернуться туда, где вы были.
Кибби
Шутки в сторону? Как я никогда не слышал об этой функции раньше ?!
Джош Хинман
4
Запустите «cmd.exe», введите «help», затем «help pushd» или «pushd /?».
paxdiablo
86
Если вы нажали на UNC-путь, он автоматически подключит диск для вас, а popd отключит его.
Ферруччо
2
+1 специально для возможностей UNC, вы должны добавить это к своему ответу.
Адам Митц
109

Не уверен, насколько это полезно в командном файле, но это очень удобная команда для использования в командной строке:

C:\some_directory> start .

Это откроет Windows Explorer в папке «some_directory».

Я нашел это очень экономит время.

LeopardSkinPillBoxHat
источник
1
ну я тоже этим пользуюсь. У меня есть файл "open.cmd" в одном из каталогов PATH, и единственное, что в этом файле, это "@start". ;)
Paulius
5
'explorer' также делает то же самое, что и 'start' C: \ some_directory> explorer.
Рэй
1
Я имею тенденцию печатать это как [начало "". ] (скобки для ясности), потому что начало иногда бывает привередливым в отношении первого параметра, являющегося заголовком.
система PAUSE
1
Если вы оказались на Mac, open .делаете то же самое.
Грант Пол
1
startделает гораздо больше, чем просто открыть текущую папку. Вы можете передать ему любой файл, и он откроется с настроенным средством просмотра. Дайте ему URL, откроется ваш браузер по умолчанию и т. Д.
idbrii
87

Мне всегда было трудно читать комментарии, помеченные ключевым словом в каждой строке:

REM blah blah blah

Легче читать:

:: blah blah blah
Крис Но
источник
8
Я слышал, что :: более эффективен, чем REM, потому что REM пытается выполнить расширение переменной окружения для того, что происходит после него, но :: нет.
Скотт Лэнгхэм
47
На самом деле, :: это просто ярлык со смешным именем; Поэтому :: не будет работать, если вы используете его внутри блока (в скобках), так как там тоже не разрешены метки. REM там работает конечно.
Михи
Обратите внимание, что remэто задокументированное ключевое слово, в то время как ::это просто деталь реализации. Хотя маловероятно, что ::он перестанет работать, в целом желательно не полагаться на недокументированное поведение.
Джои
Вы даже можете использовать goto : чтобы перейти к метке. :-)и goto -)тоже будет работать.
Свен Марнач
79

Переменные подстроки:

> set str=0123456789
> echo %str:~0,5%
01234
> echo %str:~-5,5%
56789
> echo %str:~3,-3%
3456
Крис Но
источник
3
Уродливо, но очень полезно!
Герда
1
@furtelwart звучит так, как будто это может быть девиз партии
rzrgenesys187
это отлично подходит для форматирования дат (однако проблема, которую я обнаружил, заключалась в том, что vista / 7 и xp выводили DATE по-разному)
Даниэль
Обратите внимание, что, к сожалению, это нельзя комбинировать с локальными переменными цикла FOR ( for %a in ...), поскольку они не требуют знака процента закрытия, как это делают переменные среды; Вы должны сначала назначить их переменной среды (используя отложенное расширение!), а затем извлечь подстроку.
RolKau
Это неизбежно, если вы хотите что-то сделать с датами (например, имена файлов резервных копий). Наблюдая за общим уродством командной строки Windows, я понимаю, почему Windows в большинстве случаев работает с указателями и щелчками :) Хотя говорят, что новый PowerShell лучше.
Халил Озгюр
72

Команда ЗА ! Хотя я ненавижу писать командные файлы, я благодарен за это.

FOR /F "eol=; tokens=2,3* delims=, " %i in (myfile.txt) do @echo %i %j %k

будет анализировать каждую строку в myfile.txt, игнорируя строки, начинающиеся с точки с запятой, передавая 2-й и 3-й токены из каждой строки в тело for с токенами, разделенными запятыми и / или пробелами. Обратите внимание, что операторы for body ссылаются на% i, чтобы получить 2-й токен,% j, чтобы получить 3-й токен, и% k, чтобы получить все оставшиеся токены после 3-го.

Вы также можете использовать это для перебора каталогов, содержимого каталогов и т. Д.

оборота TheSoftwareJedi
источник
4
Я обнаружил, что циклы FOR командных файлов ограничены и ужасны для записи, но иногда они полезны.
ya23
2
Извините за недоумение, но как это недостаточно используется? Я думаю, что если вы не знаете циклы FOR, вы не знаете пакетный сценарий.
Кодирование со стилем
11
Недостаточно или нет, это пытка. (Некоторые утверждают, неизбежное зло.)
Гарпо
Я должен был использовать это несколько раз, и человек, который составил этот синтаксис, должен быть уволен. Из пушки. На солнце. Это очень плохо.
VitalyB
1
@CodingWithStyle: Каждый раз, когда мне нужно написать цикл for в командном файле, сценарий становится средством запуска bash и вместо этого переписывает сценарий в bash (или python)
:)
60

Вместо того, чтобы засорять скрипт REM или :: lines, я делаю следующее в верхней части каждого скрипта:

@echo OFF
goto :START

Description of the script.

Usage:
   myscript -parm1|parm2 > result.txt

:START

Обратите внимание, как вы можете использовать символы канала и перенаправления, не экранируя их.

Патрик Кафф
источник
3
Было бы еще круче, если бы вы проверили% 1 на "/?" и тогда вы можете повторить этот раздел в качестве справочного текста.
demoncodemonkey
6
Хм, грамотное пакетное программирование ?!
Мухаммед Алкарури
54

Путь (с диском), где находится скрипт: ~ dp0

set BAT_HOME=%~dp0
echo %BAT_HOME%
cd %BAT_HOME%
RealHowTo
источник
Я обычно использую% CD% для этого. Может быть, это не доступно во всех версиях оболочки DOS?
Сол Долгин
11
% CD% - это текущий каталог, а% ~ dp0 - каталог, в котором находится исполняемый скрипт.
RealHowTo
Кроме того, я не думаю, что% CD% существовал раньше ... XP, возможно. Я знаю, что в некоторых старых версиях Windows его нет.
Томас Оуэнс
1
Вместо этого вы должны использовать cd / d% BAT_HOME%, если летучая мышь находится на другом диске. Если я правильно помню, это не будет работать со старыми DOS, хотя.
кеторин
cd или pushd% BATH_HOME% не будут работать, если вы запустите пакет по сетевому пути.
Бенуа
49

Часть% ~ dp0 уже упоминалась, но на самом деле есть еще кое-что: символы после ~ определяют извлекаемую информацию.
Отсутствие буквы приводит к возвращению имени файла исправления
d - возвращает букву диска
p - возвращает путь
s - возвращает короткий путь
x - возвращает расширение файла
Итак, если вы выполните нижеприведенный скрипт test.bat из c: \ Temp \ длинное имя каталога \ папка,

@echo off
echo %0
echo %~d0
echo %~p0
echo %~dp0
echo %~x0
echo %~s0
echo %~sp0

вы получите следующий вывод

test
c:
\Temp\long dir name\
c:\Temp\long dir name\
.bat
c:\Temp\LONGDI~1\test.bat
\Temp\LONGDI~1\

И если в ваш скрипт передается параметр, как в
test c: \ temp \ mysrc \ test.cpp,
то же самое можно сделать с переменной% 1.

Но результат расширения% 0 зависит от местоположения!
На «верхнем уровне» пакета он расширяется до текущего имени файла пакета.
В функции (вызове) она расширяется до имени функции.

@echo off
echo %0
call :test
goto :eof

:test
echo %0
echo %~0
echo %~n0

Выход (пакетный файл запускается с myBatch.bat)

myBatch.bat
:test
:test
myBatch
Хартмут
источник
43

Используя CALL, EXIT / B, SETLOCAL & ENDLOCAL, вы можете реализовать подпрограммы с локальными переменными.

пример:

@echo off

set x=xxxxx
call :sub 10
echo %x%
exit /b

:sub
setlocal
set /a x=%1 + 1
echo %x%
endlocal
exit /b

Это напечатает

11
xxxxx

хотя: sub изменяет x.

Ферруччо
источник
6
Вам лучше использовать goto: eof вместо exit / b, он делает то же самое, но это более стандартный способ сделать это.
Филибер Perusse
2
Есть стандарт для этого? О_о
Паулюс
3
Моя ошибка. Я думал, что вы имели в виду явное определение ярлыка: eof и переход к этому. Я не осознавал, что в конце каждого командного файла есть неявная метка eof.
Ферруччо
3
Однако, если вы хотите, чтобы подпрограмма установила уровень ошибки, вам нужно будет использовать exit / b. Например: выход / б 3
Крис Но
6
Я считаю, что лучше всего использовать «exit / B» вместо «goto: eof» для возврата из подпрограммы. «Goto: eof» имеет проблему, заключающуюся в том, что вы можете вернуть код ошибки, когда захотите проглотить его. Например, если вы используете «если есть someFile echo, он здесь», это установит уровень ошибки, если someFile не существует, но это не так, и это не тот код ошибки, который вы хотели бы вернуть (вот что » goto: eof "сделало бы).
Скотт Лэнгхэм
42

Подлый трюк с ожиданием N секунд (не является частью cmd.exe, но не является дополнительным программным обеспечением, поскольку он поставляется с Windows), см. Строку ping. Вам нужно N + 1 пингов, так как первый пинг проходит без задержки.

    echo %time%
    call :waitfor 5
    echo %time%
    goto :eof
:waitfor
    setlocal
    set /a "t = %1 + 1"
    >nul ping 127.0.0.1 -n %t%
    endlocal
    goto :eof
paxdiablo
источник
2
Еще лучше поместить это в файл вроде sleep.bat, чтобы избавить вас от необходимости переписывать его снова и снова.
Эрцзян
1
... и поместите файл sleep.bat в какую-то директорию в переменной окружения PATH
Scoregraphic
Я против размещения этого снаружи, делает менее переносимым ... через системы Windows.
Сорин
37

Спасаясь от «сантехники»:

echo ^| ^< ^> ^& ^\ ^^
Крис Но
источник
3
Бьюсь об заклад, побег персонажа DOS не очень известен. Хороший.
Джошуа
12
Ах, это объяснило бы, почему это также оператор продолжения строки - он экранирует символ новой строки, как \ in bash ...
leander
@leander: Да, но он может только избежать LF (а не CR), потому что все CR удалены раньше
Джеб
Так это почему использование Git на Windows , чтобы дифф против предыдущей фиксации ( HEAD^) является проблематичным.
Даниэль Треббиен
31

Возможность запуска команд и обработки выходных данных (например, обратных символов '$ ()' в bash).

for /f %i in ('dir /on /b *.jpg') do echo --^> %i

Если в именах файлов есть пробелы, используйте это:

for /f "tokens=*" %i in ('dir /on /b *.jpg') do echo --^> %i
paxdiablo
источник
2
Не работает с именами файлов, в именах которых есть пробелы ... Это работает: for / f "tokens = *"% i в ('dir / on / b * .jpg') do echo - ^>% i
Doekman
Хороший улов. Лично я думаю, что пробелы в именах файлов - это злые отвратительные вещи из глубин девятого круга ада. Но мы должны обслуживать их, я думаю.
paxdiablo
Это самый безумный синтаксис, который я когда-либо видел. Работает ли это, если вы сделали этот backtick.bat и передали строку?
idbrii
30

Создание пустого файла:

> copy nul filename.ext
nzpcmad
источник
6
@devio: эхо. ставит пустую строку. так что файл не будет пустым!
Паулюс
4
Я использую type nul > filename.extдля этого.
Бенуа
Хорошо, мне было интересно, был ли сенсорный эквивалент в течение длительного времени.
jdelator
Я всегда использовалren > blah.txt
Synetech
28

Чтобы скрыть весь вывод команды перенаправить на> nul 2> & 1.

Например, некоторые программы командной строки отображают вывод, даже если вы перенаправляете на> nul. Но если вы перенаправите вывод, как в строке ниже, все выходные будут подавлены.

PSKILL NOTEPAD >nul 2>&1

РЕДАКТИРОВАТЬ: см. Игнорирование вывода команды для объяснения того, как это работает.

оборота афория
источник
1
Вы знаете, как это работает? В чем смысл 2> & 1 бита?
Скотт Лэнгхэм
12
> Nul перенаправляет STDOUT на nul. 2> & 1 перенаправляет STDERR туда, куда указывает STDOUT.
афория
В частности, я думаю, что 2> & 1 - это «клон дескриптора файла», который устанавливает STDERR в клон STDOUT. Поместить его после> NUL важно, потому что вы хотите клонировать STDOUT после того, как он был перенаправлен, а не до. (Пожалуйста, поправьте меня, если я ошибаюсь.)
Леандер
1
Для тех из вас, кто интересуется, откуда появился PSKILL, посмотрите sysinternals.com . Если вы работаете в версии Pro, у вас должна быть собственная команда TSKILL, которая более или менее одинакова.
Кодирование со стилем
1
Если у вас нет pskill или tskill, большинство систем Windows, которые я использовал, поставляются с taskkill.
idbrii
25
PAUSE

Останавливает выполнение и отображает следующее приглашение:

Нажмите любую клавишу для продолжения . , ,

Полезно, если вы хотите запустить пакет, дважды щелкнув его в проводнике Windows, и хотите увидеть результат, а не просто всплывающее окно командной строки.

ворон
источник
Я вряд ли назвал бы это "недоиспользованным", поскольку я отмечаю это в конце каждого сценария, который я пишу. С другой стороны, это не так хорошо работает, когда вы хотите, чтобы ваша IDE запустила сценарий и захватила вывод, поскольку IDE обычно не может нажать Enter для вас ...
Николас Флинт
15
Одна из полезных функций «паузы» заключается в том, что если поблизости нет терминала для получения «любого ключа» (например, если ваш пакетный файл запускается из системной службы), он обнаруживает это и просто продолжает работать ...
leander
4
+1 Чарли Сомервиллю, это так известно, что каждый go-bat программист использовал его еще в начале 90-х.
LiraNuna
6
Вместо того, чтобы загрязнять все ваши пакетные файлы (и делать их раздражающими для использования для гиков CLI), вы можете использовать Start / Run /, а затем ввести «cmd / k» и имя пакетного файла. ИЛИ измените строку HKCR \ batfile \ shell \ open \ command default на 'cmd / k "% 1"% *'. ИЛИ создайте другой пакетный файл, который просто запускает '@cmd / k $ *', поместите его на рабочий стол и поместите на него другие свои пакетные файлы. Есть много альтернатив PAUSE. Пожалуйста, рассмотрите их.
система PAUSE
1
@gnud: вы все еще можете направить в скрипт: echo.|batch-with-pause.batбудет иметь тот же эффект, что и нажатие «любой клавиши» ...
Курт Пфайфл
25

Эквивалент bash (и других оболочек)

echo -n Hello # or
echo Hello\\c

который выводит " Hello" без завершающей строки. Чтобы сделать это с помощью команды cmd:

<nul set /p any-variable-name=Hello

set /pэто способ предложить пользователю ввести. Он генерирует заданную строку и затем ждет (в той же строке, т.е. без CRLF), чтобы пользователь набрал ответ.

<nulпросто передает пустой ответ на set /pкоманду, так что в результате получается строка выдаваемого приглашения. (Используемая переменная остается неизменной из-за пустого отклика.)

Проблемы: Невозможно вывести начальный знак равенства, а в Vista начальные пробельные символы удаляются, но не в XP.

paxdiablo
источник
18

Поиск и замена при настройке переменных среды:

> @set fname=%date:/=%

... удаляет "/" из даты для использования в именах файлов с метками времени.

и подстроки тоже ...

> @set dayofweek=%fname:~0,3%
SqlACID
источник
17

Целочисленная арифметика:

> SET /A result=10/3 + 1
4
Крис Но
источник
Как долго у SET появилась возможность рассчитывать? Windows XP?
Chakrit
1
Если вы спрашиваете, насколько большими могут быть значения, я считаю, что это 32-разрядная версия. Так что +/- 2 млрд.
Крис Но
1
Я думаю, что вопрос был в том, как долго SET смог рассчитать? С Windows XP?
Майкл Майерс
3
Мне кажется, что SET CMD.EXE может рассчитывать начиная с NT 3.1 или около того. Просто потребовалось много времени, чтобы заметить, что CMD.EXE не совсем то же самое, что COMMAND.COM ...
RBerteig
16

Разделители команд:

cls & dir
copy a b && echo Success
copy a b || echo Failure

Во второй строке команда после && выполняется только в том случае, если первая команда выполнена успешно.

На 3-й строке команда после || запускается только в случае сбоя первой команды.

doekman
источник
15

Выведите пустую строку:

echo.
paxdiablo
источник
15

Вы можете соединять операторы if для получения эффекта, подобного короткому замыканию логического `and '.

if foo if bar baz
разъем
источник
1
Это на самом деле просто ярлык для вложения ifs: if foo ( if bar ( baz ) )(представьте переводы строк после скобок.)
idbrii
14

Для быстрого преобразования текстового файла Unicode (16 бит / символ) в файл ASCII DOS (8 бит / символ).

C:\> type unicodeencoded.txt > dosencoded.txt

в качестве бонуса, если возможно, символы правильно отображаются.

RealHowTo
источник
1
Это файл ANSI DOS - ASCII 7bit / char.
MarkJ
Lol, это анти-паттерн, это преобразование, скорее всего, не удастся. Единственной 8-битной кодировкой, поддерживающей Unicode, является UTF-8, но благодаря M $ вы не можете установить кодовую страницу UTF-8 в Windows.
Сорин
14

если структура блока:

if "%VS90COMNTOOLS%"=="" (
  echo: Visual Studio 2008 is not installed
  exit /b
)
Ферруччо
источник
3
До тех пор, пока вы знаете, что переменные будут расширены все за один раз (без отложенного расширения) - то есть вы не сможете разумно использовать% ERRORLEVEL% там.
Дункан Смарт
Вы также не можете использовать метки там (которые включают в себя эти комментарии :: style), потому что это преждевременно завершит оператор if.
Кодирование со стилем
2
@Duncan: Вы %ERRORLEVEL%все равно не должны использовать псевдо-переменную ; вот для чего if errorlevel <foo>. И это действительно работает в таких блоках.
Джои
12

Задержка раскрытия переменных (с подстроками, добавленными для хорошей меры):

    @echo off
    setlocal enableextensions enabledelayedexpansion
    set full=/u01/users/pax
:loop1
    if not "!full:~-1!" == "/" (
        set full2=!full:~-1!!full2!
        set full=!full:~,-1!
        goto :loop1
    )
    echo !full!
    endlocal
paxdiablo
источник
12

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

@title Searching for ...
:: processing search
@title preparing search results
:: data processing
Хартмут
источник
2
Интересный. Хотя после этого вы, очевидно, теряете обычную функцию, которая показывает текущую команду. Есть ли способ сбросить это?
Крис Ноу
2
technet.microsoft.com/en-us/library/bb491017.aspx говорит, что он может быть сброшен с помощью «title» сам по себе, но, похоже, это не работает в Windows 7 ...
ℳ.
11

У вас нет удобного редактора, и вам нужно создать командный файл?

copy con test.bat

Просто введите команды, нажмите ввод для новой строки. Нажмите Ctrl-Z и Enter, чтобы закрыть файл.

Хартмут
источник
4
Хех, это забирает меня обратно.
Кодирование со стилем
11

Пример вычитания строки для dateи timeполучения файла с именем «ГГГГ-ММ-ДД ЧЧ: ММ: СС.txt»

echo test > "%date:~0,4%-%date:~5,2%-%date:~8,2% %time:~0,2%_%time:~3,2%_%time:~6,2%.txt"

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

цвет XY

где X и Y - шестнадцатеричное значение от 0до F, где X - фон, Y - текст, когда X = Y цвет не изменится.

цвет Z

меняет цвет текста на «Z» и устанавливает черный фон, «цвет 0» не будет работать

для названий цветов звоните

цвет ?

MoreThanChaos
источник
отредактирован; _ были интерпретированы как курсив. Хороший кусок кода.
@Duncan Smart: не соответствует действительности, также работает на английском языке в Великобритании (хотя технически это должно быть "color", grrr)
demoncodemonkey
10

Полный контроль над выводом с пробелами и escape-символами .:

echo.    ^<resourceDir^>/%basedir%/resources^</resourceDir^>
paxdiablo
источник
1
Как это работает? Точка обозначает начало текстового вывода?
Крис Ноу
3
«echo. x» выведет «<пробел> x», «echo x» выведет только «x». Это позволяет ведущие пробелы. Кроме того, экранирующий символ «^» не позволит cmd думать, что все эти символы «<» и «>» являются перенаправлением ввода-вывода.
paxdiablo
1
echo (лучше, потому что echo. создает поиск файла для файла с именем "echo", если этот файл существует, echo. происходит сбой, если нет, то выполняется внутреннее echo, но оно медленнее, чем echo (
jeb
9

TheSoftwareJedi уже упоминал команду for, но я собираюсь упомянуть ее еще раз, поскольку она очень мощная.

Ниже выводится текущая дата в формате ГГГГММДД, я использую ее при создании каталогов для резервных копий.

for /f "tokens=2-4 delims=/- " %a in ('DATE/T') do echo %c%b%a
remonedo
источник
2
Конечно, DATE / T возвращается 29/10/2008 в Европе и 29.10.2008 в США ... поэтому может потребоваться некоторая локализация! ;-)
Это правильно! Но вы можете использовать команду date, чтобы узнать, какой формат даты используется.
remonedo
4
Это чрезмерное использование FOR, IMO. Я думаю, что я просто использовал бы% DATE: ~ 10,4 %% DATE: ~ 4,2 %% DATE: ~ 7,2%, вместо того, чтобы запускать команду date, а затем анализировать ее.
Кодирование со стилем