É possível escrever um único arquivo de script que seja executado no Windows (tratado como .bat) e no Linux (via Bash)?
Eu conheço a sintaxe básica de ambos, mas não descobri. Ele provavelmente poderia explorar alguma sintaxe obscura do Bash ou alguma falha do processador de lote do Windows.
O comando a ser executado pode ser apenas uma única linha para executar outro script.
A motivação é ter apenas um único comando de inicialização do aplicativo para Windows e Linux.
Atualização: A necessidade de um script de shell "nativo" do sistema é que ele precisa escolher a versão correta do interpretador, em conformidade com certas variáveis de ambiente conhecidas, etc. A instalação de ambientes adicionais como o CygWin não é preferível - eu gostaria de manter o conceito " baixar e executar ".
O único outro idioma a ser considerado para o Windows é o Windows Scripting Host - WSH, que é predefinido por padrão desde 98.
fonte
cp
embutidos, ou vice-versa, então escrever dois scripts separados pode ser pedagogicamente melhor do que as técnicas avançadas mostradas aqui.Respostas:
O que fiz foi usar a sintaxe de rótulo do cmd como marcador de comentário . O caractere de rótulo, dois pontos (
:
), é equivalentetrue
na maioria dos shells POSIXish. Se você seguir imediatamente o caractere do rótulo por outro caractere que não pode ser usado em aGOTO
, comentar seucmd
script não deve afetar seucmd
código.O truque é colocar linhas de código após a sequência de caracteres “
:;
”. Se você está escrevendo principalmente scripts de uma linha ou, como pode ser o caso, pode escrever uma linhash
para várias linhas decmd
, o seguinte pode ser adequado. Não se esqueça de que qualquer uso de$?
deve ser antes de seus próximos dois pontos:
porque:
redefine$?
para 0.Um exemplo muito inventado de guarda
$?
:Outra ideia para pular
cmd
código é usar heredocs para quesh
trate ocmd
código como uma string não usada e ocmd
interprete. Nesse caso, certificamo-nos de que o delimitador de nosso heredoc está entre aspas (para pararsh
de fazer qualquer tipo de interpretação em seu conteúdo ao executar comsh
) e começa com de:
modo que ocmd
pule como qualquer outra linha começando com:
.Dependendo das suas necessidades ou estilo de codificação, o entrelaçamento
cmd
e osh
código podem ou não fazer sentido. Usar heredocs é um método para realizar esse entrelaçamento. Isso poderia, no entanto, ser estendido com aGOTO
técnica :Os comentários universais, é claro, podem ser feitos com a sequência de caracteres
: #
ou:;#
. O espaço ou ponto-e-vírgula são necessários porquesh
considera#
-se parte de um nome de comando se não for o primeiro caractere de um identificador. Por exemplo, você pode querer escrever comentários universais nas primeiras linhas de seu arquivo antes de usar oGOTO
método para dividir seu código. Em seguida, você pode informar ao leitor por que seu script foi escrito de forma tão estranha:Assim, algumas idéias e maneiras de realizar
sh
e -cmd
scripts compatíveis sem efeitos colaterais graves, pelo que eu sei (e semcmd
saída'#' is not recognized as an internal or external command, operable program or batch file.
).fonte
.cmd
extensão, caso contrário, ele não será executado no Windows. Existe alguma solução alternativa?.cmd
e marcá-los como executáveis. Dessa forma, a execução do script do shell padrão no Windows ou no Unix funcionará (testado apenas com o bash). Como não consigo pensar em uma maneira de incluir um shebang sem fazer cmd reclamar em voz alta, você deve sempre invocar o script via shell.execlp()
Ou seja, certifique-se de usar ouexecvp()
(acho quesystem()
é a maneira “certa” para você) em vez deexecl()
ouexecv()
(essas últimas funções só funcionam em scripts com shebangs porque vão mais diretamente para o sistema operacional).<Exec/>
MSBuild Task ) em vez de arquivos em lote independentes. Talvez se eu tiver algum tempo no futuro eu atualizarei a resposta com as informações desses comentários…você pode tentar isto:
Provavelmente você precisará usar
/r/n
como uma nova linha em vez de um estilo unix. Se bem me lembro, a nova linha unix não é interpretada como uma nova linha por.bat
scripts. Outra maneira é criar um#.exe
arquivo no caminho que não faz nada em maneira semelhante à minha resposta aqui: É possível incorporar e executar VBScript em um arquivo em lote sem usar um arquivo temporário?EDITAR
A resposta do binki é quase perfeita, mas ainda pode ser melhorada:
Ele usa novamente o
:
truque e o comentário de várias linhas. Parece cmd.exe (pelo menos no windows10) funciona sem problemas com os EOLs de estilo unix, então certifique-se de que seu script seja convertido para o formato linux. (a mesma abordagem já foi usada antes aqui e aqui ). Embora o uso de shebang ainda produza saída redundante ...fonte
/r/n
no final das linhas causará muitas dores de cabeça no script bash, a menos que você termine cada linha com um#
(ou seja#/r/n
) - dessa forma, o\r
será tratado como parte do comentário e ignorado.# 2>NUL & ECHO Welcome to %COMSPEC%.
consegue esconder o erro sobre o#
comando não ser encontrado porcmd
. Esta técnica é útil quando você precisa escrever uma linha independente que só será executada porcmd
( por exemplo, em aMakefile
).Eu queria comentar, mas só posso adicionar uma resposta no momento.
As técnicas dadas são excelentes e eu também as uso.
É difícil reter um arquivo que contém dois tipos de quebras de linha, sendo
/n
para a parte bash e/r/n
para a parte windows. A maioria dos editores tenta impor um esquema de quebra de linha comum, adivinhando que tipo de arquivo você está editando. Além disso, a maioria dos métodos de transferência de arquivo pela Internet (particularmente como um arquivo de texto ou script) irá iniciar as quebras de linha, portanto, você pode começar com um tipo de quebra de linha e terminar com o outro. Se você fez suposições sobre quebras de linha e, em seguida, deu seu script para outra pessoa usar, ela pode descobrir que não funciona para ela.O outro problema são os sistemas de arquivos montados em rede (ou CDs) que são compartilhados entre diferentes tipos de sistema (particularmente quando você não pode controlar o software disponível para o usuário).
Deve-se, portanto, usar a quebra de linha do DOS
/r/n
e também proteger o script bash do DOS/r
, colocando um comentário no final de cada linha (#
). Você também não pode usar continuações de linha no bash porque o/r
fará com que quebrem.Desta forma, quem usar o script, em qualquer ambiente, ele funcionará.
Eu uso esse método junto com a criação de Makefiles portáteis!
fonte
O que segue funciona para mim sem erros ou mensagens de erro com Bash 4 e Windows 10, ao contrário das respostas acima. Eu chamo o arquivo de "qualquer coisa.cmd", faço
chmod +x
para torná-lo executável no linux e faço com que tenha terminações de linha unix (dos2unix
) para manter o bash silencioso.fonte
Você pode compartilhar variáveis:
fonte
Existem várias maneiras de executar comandos diferentes sobre
bash
ecmd
com o mesmo script.cmd
irá ignorar as linhas que começam com:;
, conforme mencionado em outras respostas. Ele também irá ignorar a próxima linha se a linha atual terminar com o comandorem ^
, pois o^
caractere escapará da quebra de linha e a próxima linha será tratada como um comentário derem
.Quanto a fazer
bash
ignorar ascmd
linhas, existem várias maneiras. Eu enumerei algumas maneiras de fazer isso sem quebrar oscmd
comandos:#
Comando inexistente (não recomendado)Se não houver nenhum
#
comando disponívelcmd
quando o script for executado, podemos fazer o seguinte:O
#
caractere no início dacmd
linha faz combash
que trate essa linha como um comentário.O
#
personagem no final dabash
linha é usado para comentar o\r
personagem, como Brian Tompsett apontou em sua resposta . Sem isso,bash
será gerado um erro se o arquivo tiver\r\n
terminações de linha, exigidas porcmd
.Ao fazer
# 2>nul
isso, estamos enganandocmd
para ignorar o erro de algum#
comando inexistente , enquanto ainda executamos o comando a seguir.Não use esta solução se houver um
#
comando disponível noPATH
ou se você não tiver controle sobre os comandos disponíveis paracmd
.Usando
echo
para ignorar o#
personagem emcmd
Podemos usar
echo
com sua saída redirecionada para inserircmd
comandos nabash
área comentada de:Como o
#
caractere não tem nenhum significado especialcmd
, ele é tratado como parte do texto paraecho
. Tudo o que precisamos fazer é redirecionar a saída doecho
comando e inserir outros comandos depois dele.#.bat
Arquivo vazioA
echo >/dev/null # 1>nul 2> #.bat
linha cria um#.bat
arquivo vazio enquanto ligadocmd
(ou substitui o existente#.bat
, se houver) e não faz nada enquanto está ligadobash
.Este arquivo será usado pela
cmd
(s) linha (s) que segue, mesmo se houver algum outro#
comando noPATH
.O
del #.bat
comando nocmd
código específico exclui o arquivo que foi criado. Você só precisa fazer isso na últimacmd
linha.Não use esta solução se um
#.bat
arquivo puder estar em seu diretório de trabalho atual, pois esse arquivo será apagado.Recomendado: usar here-document para ignorar
cmd
comandos embash
Ao colocar o
^
caractere no final dacmd
linha, estamos escapando da quebra de linha e usando:
como delimitador here-document, o conteúdo da linha delimitadora não terá efeitocmd
. Dessa forma,cmd
só executará sua linha após o término da:
linha, tendo o mesmo comportamento quebash
.Se quiser ter várias linhas em ambas as plataformas e executá-las apenas no final do bloco, você pode fazer o seguinte:
Desde que não haja uma
cmd
linha exatahere-document delimiter
, essa solução deve funcionar. Você pode mudarhere-document delimiter
para qualquer outro texto.Em todas as soluções apresentadas, os comandos só serão executados após a última linha , tornando seu comportamento consistente se fizerem a mesma coisa nas duas plataformas.
Essas soluções devem ser salvas em arquivos com
\r\n
quebras de linha, caso contrário, não funcionarãocmd
.fonte
As respostas anteriores parecem cobrir praticamente todas as opções e me ajudaram muito. Estou incluindo esta resposta aqui apenas para demonstrar o mecanismo que usei para incluir um script Bash e um script Windows CMD no mesmo arquivo.
LinuxWindowsScript.bat
Resumo
Em Linux
A primeira linha (
echo >/dev/null # >nul & GOTO WINDOWS & rem ^
) será ignorada e o script fluirá por cada linha imediatamente a seguir até que oexit 0
comando seja executado. Assim queexit 0
for atingido, a execução do script será encerrada, ignorando os comandos do Windows abaixo dele.No Windows
A primeira linha executará o
GOTO WINDOWS
comando, pulando os comandos do Linux imediatamente a seguir e continuando a execução na:WINDOWS
linha.Removendo devoluções de carro no Windows
Como estava editando este arquivo no Windows, tive que remover sistematicamente os retornos de carro (\ r) dos comandos do Linux ou obtive resultados anormais ao executar a parte do Bash. Para fazer isso, abri o arquivo no Notepad ++ e fiz o seguinte:
Ative a opção para visualizar o final da linha (
View
>Show Symbol
>Show End of Line
). Os retornos de carro serão exibidos comoCR
caracteres.Faça um Localizar e Substituir (
Search
>Replace...
) e marque aExtended (\n, \r, \t, \0, \x...)
opção.Digite
\r
noFind what :
campo e em branco oReplace with :
campo para que não haja nada nele.Começando na parte superior do arquivo, clique no
Replace
botão até que todos osCR
caracteres de retorno de carro ( ) tenham sido removidos da parte superior do Linux. Certifique-se de deixar osCR
caracteres de retorno de carro ( ) para a parte do Windows.O resultado deve ser que cada comando do Linux termina em apenas um avanço de linha (
LF
) e cada comando do Windows termina em um retorno de carro e avanço de linha (CR
LF
).fonte
Eu uso essa técnica para criar arquivos jar executáveis. Como o arquivo jar / zip começa no cabeçalho zip, posso colocar um script universal para executar este arquivo no topo:
@
in sh gera um erro que é canalizado/dev/null
e, depois disso, um comentário é iniciado. No cmd, o pipe para/dev/null
falha porque o arquivo não é reconhecido no Windows, mas como o Windows não detecta#
como um comentário, o erro é redirecionadonul
. Em seguida, ele faz um eco off. Como a linha inteira é precedida por um,@
ela não é impressa no cmd.::
, que inicia um comentário em cmd, para noop em sh. Isso tem o benefício que::
não é redefinido$?
como0
. Ele usa o:;
truque " é um rótulo".::
e eles são ignorados no cmd:: exit
as extremidades de script sh e posso escrever comandos cmdcommand not found
. Você tem que decidir por si mesmo se precisa ou não.fonte
Eu precisava disso para alguns dos meus scripts de instalação de pacote Python. A maioria das coisas entre o arquivo sh e bat são as mesmas, mas poucas coisas como o tratamento de erros são diferentes. Uma maneira de fazer isso é a seguinte:
Então você chama isso do script bash:
O arquivo em lote do Windows tem a seguinte aparência:
fonte
Tente meu projeto BashWin em https://github.com/skanga/bashwin que usa BusyBox para a maioria dos comandos Unix
fonte
Existem ferramentas de construção independentes de plataforma como Ant ou Maven com sintaxe xml (baseada em Java). Assim, você pode reescrever todos os seus scripts no Ant ou Maven e executá-los, independentemente do tipo de sistema operacional. Ou você pode simplesmente criar um script Ant wrapper, que irá analisar o tipo de sistema operacional e executar o bat ou o script bash apropriado.
fonte