Можно ли написать один файл сценария, который будет выполняться как в Windows (обрабатывается как .bat), так и в Linux (через Bash)?
Я знаю базовый синтаксис обоих, но не понял. Вероятно, он мог использовать неясный синтаксис Bash или какой-то сбой пакетного процессора Windows.
Команда для выполнения может быть просто одной строкой для выполнения другого сценария.
Мотивация состоит в том, чтобы иметь только одну команду загрузки приложения для Windows и Linux.
Обновление: необходимость в «родном» сценарии оболочки заключается в том, что он должен выбрать правильную версию интерпретатора, соответствовать определенным хорошо известным переменным среды и т. Д. Установка дополнительных сред, таких как CygWin, не является предпочтительной - я хотел бы сохранить эту концепцию " скачать и запустить ".
Единственный другой язык, который следует учитывать для Windows, - это Windows Scripting Host - WSH, который установлен по умолчанию с 98.
источник
cp
встроенные или наоборот, поэтому написание двух отдельных сценариев может быть педагогически лучше, чем продвинутые методы, показанные здесь.Ответы:
Что я сделал, так это использовал синтаксис метки cmd в качестве маркера комментария . Символ метки, двоеточие (
:
), эквивалентенtrue
большинству POSIX-оболочек. Если вы сразу же следуете за символом метки другим символом, который нельзя использовать вGOTO
, то комментирование вашегоcmd
скрипта не должно повлиять на вашcmd
код.Хакерство заключается в том, чтобы поместить строки кода после последовательности символов «
:;
». Если вы пишете в основном однострочные сценарии или, в некоторых случаях, можете написать одну строкуsh
на несколько строкcmd
, следующее может подойти. Не забывайте, что любое использование$?
должно быть перед следующим двоеточием,:
потому что:
сбрасывается$?
на 0.Очень надуманный пример охраны
$?
:Еще одна идея пропуска
cmd
кода - использовать heredocs, чтобыsh
обрабатыватьcmd
код как неиспользуемую строку иcmd
интерпретировать ее. В этом случае мы гарантируем, что разделитель нашего heredoc заключен в кавычки (чтобы прекратитьsh
какую-либо интерпретацию его содержимого при работе сsh
) и начинается с,:
чтобыcmd
пропускать его, как любую другую строку, начинающуюся с:
.В зависимости от ваших потребностей или стиля кодирования чересстрочная развертка
cmd
иsh
код могут иметь или не иметь смысла. Использование heredocs - один из способов выполнения такого чередования. Однако это можно расширить с помощьюGOTO
техники :Универсальные комментарии, конечно, можно делать с помощью последовательности символов
: #
или:;#
. Пробел или точка с запятой необходимы, потому что ониsh
считаются#
частью имени команды, если они не являются первым символом идентификатора. Например, вы можете захотеть написать универсальные комментарии в первых строках файла, прежде чем использовать этотGOTO
метод для разделения кода. Затем вы можете сообщить своему читателю, почему ваш скрипт написан так странно:Таким образом, некоторые идеи и способы выполнения
sh
иcmd
совместимости скриптов без серьезных побочных эффектов, насколько мне известно (и безcmd
вывода'#' is not recognized as an internal or external command, operable program or batch file.
).источник
.cmd
расширение, иначе он не будет работать в Windows. Есть ли обходной путь?.cmd
и пометить как исполняемые. Таким образом, выполнение сценария из оболочки по умолчанию в Windows или unix будет работать (проверено только с помощью bash). Поскольку я не могу придумать способ включить shebang, не заставляя cmd громко жаловаться, вы всегда должны вызывать сценарий через оболочку. Т.е. обязательно используйтеexeclp()
илиexecvp()
(я думаюsystem()
, это «правильный» для вас способ), а неexecl()
илиexecv()
(эти последние функции будут работать только в сценариях с shebang, потому что они идут напрямую в ОС).<Exec/>
MSBuild Task ), а не в виде независимых пакетных файлов. Может быть, если у меня будет время в будущем, я дополню ответ информацией из этих комментариев…вы можете попробовать это:
Вероятно, вам нужно будет использовать
/r/n
как новую строку вместо стиля unix. Если я правильно помню, новая строка unix не интерпретируется скриптами как новая строка..bat
Другой способ - создать#.exe
файл в пути, который ничего не делает в аналогично моему ответу здесь: можно ли встроить и выполнить VBScript в пакетном файле без использования временного файла?РЕДАКТИРОВАТЬ
В ответ Бинки в почти совершенна , но все еще можно улучшить:
Он снова использует
:
уловку и многострочный комментарий. Похоже, cmd.exe (по крайней мере, на windows10) работает без проблем с EOL в стиле unix, поэтому убедитесь, что ваш скрипт преобразован в формат linux. (такой же подход использовался раньше здесь и здесь ). Хотя использование shebang по-прежнему будет производить избыточный вывод ...источник
/r/n
в конце строк вызовет много головной боли в сценарии bash, если вы не заканчиваете каждую строку знаком#
(т.е.#/r/n
) - в этом случае\r
они будут рассматриваться как часть комментария и игнорироваться.# 2>NUL & ECHO Welcome to %COMSPEC%.
удается скрыть ошибку о том, что#
команда не найденаcmd
. Этот метод полезен, когда вам нужно написать отдельную строку, которая будет выполняться толькоcmd
(например, в aMakefile
).Я хотел прокомментировать, но пока могу только добавить ответ.
Приведены отличные техники, и я их тоже использую.
Трудно сохранить файл, в котором содержатся два типа разрывов строк:
/n
для части bash и/r/n
для части Windows. Большинство редакторов пытаются применить общую схему разрыва строки, угадывая, какой файл вы редактируете. Кроме того, большинство методов передачи файла через Интернет (в частности, в виде текстового файла или файла сценария) запускают разрывы строк, поэтому вы можете начать с одного вида разрыва строки и закончить другим. Если вы сделали предположения о переносах строк, а затем передали свой сценарий кому-то другому, они могут обнаружить, что он не работает для них.Другая проблема связана с сетевыми файловыми системами (или компакт-дисками), которые используются разными типами систем (особенно в тех случаях, когда вы не можете управлять программным обеспечением, доступным пользователю).
Поэтому следует использовать разрыв строки DOS,
/r/n
а также защищать сценарий bash от DOS/r
, помещая комментарий в конце каждой строки (#
). Вы также не можете использовать продолжения строк в bash, потому что это/r
приведет к их разрыву.Таким образом, кто бы ни использовал сценарий и в любой среде, он будет работать.
Я использую этот метод вместе с созданием переносимых файлов Makefile!
источник
Следующее работает для меня без каких-либо ошибок или сообщений об ошибках с Bash 4 и Windows 10, в отличие от ответов выше. Я называю файл «something.cmd», делаю
chmod +x
его исполняемым в linux, и добавляю в него окончания строки unix (dos2unix
), чтобы bash не работал.источник
Есть несколько способов выполнения разных команд в одном
bash
иcmd
том же скрипте.cmd
будет игнорировать строки, начинающиеся с:;
, как упоминалось в других ответах. Он также проигнорирует следующую строку, если текущая строка заканчивается командойrem ^
, так как^
символ выйдет за пределы разрыва строки, а следующая строка будет рассматриваться как комментарийrem
.Что касается
bash
игнорированияcmd
строк, существует несколько способов. Я перечислил несколько способов сделать это, не нарушаяcmd
команды:Несуществующая
#
команда (не рекомендуется)Если при запуске скрипта нет
#
доступных командcmd
, мы можем сделать это:Символ
#
в началеcmd
строки заставляетbash
рассматривать эту строку как комментарий.Символ
#
в концеbash
строки используется для комментирования\r
персонажа, как указал Брайан Томпсетт в своем ответе . Без этогоbash
будет выдана ошибка, если в файле есть\r\n
окончания строк, требуемыеcmd
.Поступая так
# 2>nul
, мы пытаемсяcmd
игнорировать ошибку какой-то несуществующей#
команды, продолжая выполнять следующую команду.Не используйте это решение, если есть
#
команда, доступная на сайте,PATH
или если у вас нет контроля над командами, доступными дляcmd
.Использование
echo
для игнорирования#
символа наcmd
Мы можем использовать
echo
его перенаправленный вывод для вставкиcmd
команд вbash
закомментированную область:Поскольку этот
#
символ не имеет особого значенияcmd
, он рассматривается как часть текстаecho
. Все, что нам нужно было сделать, это перенаправить выводecho
команды и вставить после нее другие команды.Пустой
#.bat
файлecho >/dev/null # 1>nul 2> #.bat
Строка создает пустой#.bat
файл при положеннойcmd
(или заменяет существующие#.bat
, если таковые имеются), и ничего не делает при положеннойbash
.Этот файл будет использоваться
cmd
линиями (ы) , что следует , даже если есть какая -либо другая#
команда наPATH
.Команда
del #.bat
вcmd
конкретном коде удаляет созданный файл. Вам нужно сделать это только в последнейcmd
строке.Не используйте это решение, если
#.bat
файл может находиться в вашем текущем рабочем каталоге, так как этот файл будет удален.Рекомендуется: использовать здесь-документ для игнорирования
cmd
команд наbash
Помещая
^
символ в концеcmd
строки, мы экранируем разрыв строки, и используя:
в качестве разделителя здесь-документа, содержимое строки разделителя не будет иметь никакого эффектаcmd
. Таким образом, онcmd
будет выполнять свою строку только после того, как:
строка закончится, имея такое же поведение, какbash
.Если вы хотите иметь несколько строк на обеих платформах и выполнять их только в конце блока, вы можете сделать это:
Это решение должно работать, пока нет
cmd
строки с точнымhere-document delimiter
. Вы можете изменитьhere-document delimiter
на любой другой текст.Во всех представленных решениях команды будут выполняться только после последней строки , что делает их поведение согласованным, если они делают одно и то же на обеих платформах.
Эти решения должны быть сохранены в файлах с
\r\n
разрывами строк, иначе они не будут работатьcmd
.источник
Вы можете поделиться переменными:
источник
Предыдущие ответы, похоже, охватывают почти все варианты и очень мне помогли. Я включаю этот ответ сюда, чтобы продемонстрировать механизм, который я использовал для включения сценария Bash и сценария Windows CMD в один и тот же файл.
LinuxWindowsScript.bat
Резюме
В Linux
Первая строка (
echo >/dev/null # >nul & GOTO WINDOWS & rem ^
) будет проигнорирована, и сценарий будет проходить через каждую строку сразу после нее, покаexit 0
команда не будет выполнена. Как только этоexit 0
будет достигнуто, выполнение скрипта завершится, игнорируя команды Windows под ним.В Windows
Первая строка выполнит
GOTO WINDOWS
команду, пропуская команды Linux, следующие сразу за ней, и продолжит выполнение в:WINDOWS
строке.Удаление возврата каретки в Windows
Поскольку я редактировал этот файл в Windows, мне приходилось систематически удалять символы возврата каретки (\ r) из команд Linux, иначе я получил ненормальные результаты при запуске части Bash. Для этого я открыл файл в Notepad ++ и сделал следующее:
Включите опцию для просмотра символа конца строки (
View
>Show Symbol
>Show End of Line
). Возврат каретки будет отображаться какCR
символы.Выполните «Найти и заменить» (
Search
>Replace...
) и установитеExtended (\n, \r, \t, \0, \x...)
флажок.Тип
\r
вFind what :
поле и заготовки внеReplace with :
поля , так что нет ничего в нем.Начиная с верхней части файла, нажимайте
Replace
кнопку, пока всеCR
символы возврата каретки ( ) не будут удалены из верхней части Linux. Обязательно оставьтеCR
символы возврата каретки ( ) для части Windows.Результатом должно быть то, что каждая команда Linux заканчивается только переводом строки (
LF
), а каждая команда Windows заканчивается возвратом каретки и переводом строки (CR
LF
).источник
Я использую эту технику для создания исполняемых файлов jar. Поскольку файл jar / zip начинается с заголовка zip, я могу поместить универсальный скрипт для запуска этого файла вверху:
@
in sh выдает ошибку, которая передается по конвейеру,/dev/null
и после этого начинается комментарий. В cmd канал/dev/null
не работает, потому что файл не распознается в окнах, но поскольку окна не обнаруживают#
как комментарий, ошибка передается по конвейеруnul
. Затем отключается эхо. Поскольку всей строке предшествует,@
она не выводится на печать в cmd.::
, с которого начинается комментарий в cmd, до noop в sh. Это имеет то преимущество , что::
не приводит к сбросу$?
в0
. Он использует:;
уловку « это ярлык».::
и они игнорируются в cmd:: exit
завершении скрипта sh я могу писать команды cmdcommand not found
. Вам это нужно или нет, решать вам.источник
Мне это нужно для некоторых сценариев установки пакетов Python. Большинство вещей между sh и bat файлом одинаковы, но некоторые вещи, такие как обработка ошибок, отличаются. Один из способов сделать это:
Затем вы вызываете это из сценария bash:
Пакетный файл Windows выглядит так:
источник
Попробуйте мой проект BashWin на https://github.com/skanga/bashwin, который использует BusyBox для большинства команд Unix
источник
Существуют независимые от платформы инструменты сборки, такие как Ant или Maven с синтаксисом xml (на основе Java). Таким образом, вы можете переписать все свои скрипты в Ant или Maven и запустить их независимо от типа ОС. Или вы можете просто создать сценарий оболочки Ant, который проанализирует тип ОС и запустит соответствующий сценарий bat или bash.
источник