Моим текущим предпочтением для этой задачи является заголовок полиглота, который работает почти так же, как первое решение mklement0 :
<# :cmd header for PowerShell script
@ set dir=%~dp0
@ set ps1="%TMP%\%~n0-%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%.ps1"
@ copy /b /y "%~f0" %ps1% >nul
@ powershell -NoProfile -ExecutionPolicy Bypass -File %ps1% %*
@ del /f %ps1%
@ goto :eof
#>
# Paste arbitrary PowerShell code here.
# In this example, all arguments are echoed.
$Args | % { 'arg #{0}: [{1}]' -f ++$i, $_ }
Я предпочитаю размещать заголовок cmd в виде нескольких строк с одной командой для каждой по ряду причин. Во-первых, я думаю, что легче понять, что происходит: командные строки достаточно короткие, чтобы не выходить за пределы правого окна редактирования, а столбец пунктуации слева помечает его визуально как блок заголовка, на котором написано ужасно злоупотребленное обозначение. первая строка говорит, что это так. Во-вторых, команды del
и goto
находятся в своих собственных строках, поэтому они по-прежнему будут выполняться, даже если что-то действительно прикольное будет передано в качестве аргумента сценария.
Я предпочел решения, которые создают временный файл .ps1
, а не те, которые основаны на Invoke-Expression
, просто потому, что непостижимые сообщения об ошибках PowerShell будут, по крайней мере, содержать значащие номера строк.
Время, затрачиваемое на создание временного файла, обычно полностью затопляется к тому времени, когда сам PowerShell начинает работать, а значение %RANDOM%
на 128 бит, встроенное в имя временного файла, в значительной степени гарантирует выигрыш нескольких одновременных сценариев. никогда не топайте друг друга временными файлами. Единственный реальный недостаток подхода временных файлов - это возможная потеря информации о каталоге, из которого был вызван исходный сценарий cmd, что является обоснованием для переменной среды dir
, созданной во второй строке.
Очевидно, что для PowerShell было бы гораздо меньше раздражать, если бы он не был настолько внимателен к расширениям файлов, которые он будет принимать в файлах сценариев, но вы вступаете в войну с имеющейся у вас оболочкой, а не с той оболочкой, которую вы хотели бы иметь.
Кстати, о чем: как замечает mklement0,
# BREAKS, due to the `&` inside \"...\"
sample.cmd "A \"rock & roll\" life style"
Это действительно нарушается из-за абсолютно бесполезного разбора аргументов cmd.exe
. Я обычно обнаружил, что чем меньше я работаю, чтобы попытаться скрыть cmd многие ограничения, тем меньше непредвиденных ошибок я вывожу на себя (я уверен, что мог бы придумать аргументы, содержащие скобки, которые сломали бы Например, безупречный амперсанд и уходящая логика у mklement0). Менее болезненно, на мой взгляд, просто прикусить пулю и использовать что-то вроде
sample.cmd "A \"rock ^^^& roll\" life style"
Первый и третий ^
побеги съедаются при первоначальном анализе этой командной строки; второй выживает, спасаясь от &
, встроенного в командную строку, переданного powershell.exe
. Да, это безобразно Да, становится все труднее делать вид, что cmd.exe
- это не то, что первым дает трещину в скрипте. Не беспокойся об этом. Запишите это, если это имеет значение.
В большинстве реальных приложений проблема &
спорна в любом случае. Большая часть того, что будет передаваться в качестве аргументов в скрипт, подобный этому, будет путями, которые приходят с помощью перетаскивания. Windows будет заключать в кавычки те, которых достаточно для защиты пробелов и амперсандов, и фактически ничего, кроме кавычек, которые в любом случае недопустимы в путевых именах Windows.
Даже не заводите меня на Vinyl LP's, 12"
в CSV-файле.