Desafio : escreva um único arquivo de script foo.cmd
que possa ser chamado no cmd.exe
prompt do Windows, baunilha (não no PowerShell, não no modo administrador), para executar códigos arbitrários específicos do Windows ...
> .\foo.cmd
Hello Windows!
... mas também ser invocado inalterado de um típico compatível com POSIX (Linux / OSX) janela de comandos ( bash
, tcsh
ou zsh
), para executar arbitrária código específico do POSIX:
$ chmod a+x foo.cmd
$ ./foo.cmd
Hello POSIX!
... sem a necessidade de instalação ou criação de intérpretes / ferramentas de terceiros.
Eu sei que isso é possível, mas com cruft (ou seja, no Windows, uma ou duas linhas de lixo / mensagem de erro são impressas em stderr ou stdout antes de "Hello Windows!").
O critério vencedor é a minimização (primeiro) do número de linhas de cruft e (segundo) do número de caracteres de cruft.
Cruft pode ser definido como qualquer saída do console (stdout ou stderr) que não seja produzida pelo código de carga útil (arbitrária). As linhas em branco são contadas na contagem de linhas. Novas linhas não são contadas na contagem de caracteres. As pontuações de cruft devem ser somadas nas duas plataformas. Vamos desconsiderar mecanismos como cls
esse que varrem a crosta, mas com o custo de também anular a saída anterior do terminal. Se o Windows repetir seus comandos porque você ainda não ativou @echo off
, vamos excluir os caracteres que ele gasta na impressão do diretório e prompt atuais.
Um critério secundário é a simplicidade / elegância da solução interna foo.cmd
: se "infraestrutura" for definida como qualquer caractere não diretamente envolvido no código de carga arbitrária, minimize primeiro o número de linhas que contêm caracteres de infraestrutura e depois o número total de infraestrutura personagens.
Parabéns extra se a parte do POSIX funcionar apesar do arquivo ter terminações de linha CRLF! (Não tenho certeza de que a última parte seja possível.)
Minha solução existente, que postarei aqui depois que outros tiverem chance, usa 6 linhas de código de infraestrutura (52 caracteres, excluindo novas linhas). Ele produz 5 linhas de cruft, duas das quais estão em branco, todas ocorrendo no Windows (30 caracteres excluindo novas linhas e excluindo a cadeia de diretório / prompt atual que aparece em duas dessas linhas).
Respostas:
0 linhas de cruft, 0 caracteres de cruft, 2 infra. linhas, 21 infra. caracteres, CRLF ok
Removida a outra solução.
17 caracteres usando
exit /b
a resposta do Digital Trauma:fonte
: command not found
sempre que uma linha em branco entrava na carga útil posix, mas finalmente descobri que não estava:
na primeira linha, mas sim por causa de CRLFs desprotegidos por ela#
. Foi novidade para mim que uma#!
linha não é necessária - que foi responsável por duas das linhas de cruft do Windows na minha versão anterior.: ` >&3` \
a todas as linhas da carga útil, acho que você poderia dizer que o custo da infraestrutura é arbitrariamente alto.#
necessário?Pontuação 0 cruft + 4 infra-linhas + 32 infra-caracteres. LF e CRLF OK.
Isso se baseia no que encontrei neste blog , com os bits Amiga e outras linhas desnecessárias removidas. Eu escondi as linhas do DOS entre aspas comentadas, em vez de
\
continuar usando a linha, para que isso funcione com o CRLF e o LF.Com as terminações de linha DOS CRLF ou * nix LF, ele funciona no Ubuntu, OSX e wine:
Para criar isso exatamente (com CRLFs) em uma máquina * nix (incluindo OSX), cole o seguinte em um terminal:
fonte
dosix
também é um nome legal. Mas no meu Mac (OS 10.9.4, Darwin Kernel versão 13.3.0, GNU bash versão 3.2.51) ele falha ao ser executado com:./dosix.cmd: line 13: syntax error: unexpected end of file
Alguma idéia de por quê?Já vou postar a solução que estava usando, pois já foi vencida. É cortesia de um colega meu que acho que deve ter lido a mesma entrada de blog que o Digital Trauma .
#!
linha não se importar (portanto, para intérpretes padrão comosh
amigos e amigos, ele falha)fonte
#!
, o que significa que a sua é a única resposta até agora para ser um script válido em um sistema POSIX. Certamente alguns dos outros podem executar se - mas somente se forem iniciados a partir de um shell com uma solução alternativa para scripts com defeito.#!
linha, mas eles usarão shells diferentes para interpretar o script. Isso significa que um "script" que não começa#!
deve ser válido não apenas em um shell, mas em todos os shell pelos quais possa ser plausivelmente interpretado. Pior ainda, só funciona ao ser iniciado a partir de outro shell. Esse script pode funcionar na linha de comando, mas não no contexto em que você finalmente pretende usá-lo.#!
linha na minha resposta editada (1 linha de infra-estrutura com 21 caracteres) pode ser combinada com a resposta de qualquer outra pessoa a um custo de apenas duas linhas do Windows (somente uma em branco) ou 23 caracteres.Resumo / síntese de respostas e discussão
Isso foi divertido, e eu aprendi muito.
Alguns itens específicos do Windows são inevitáveis se, no seu sistema POSIX, você precisar iniciar o script com uma
#!
linha. Se você não tem alternativa a não ser fazer isso, então esta linha:é provavelmente o melhor que pode obter. Isso faz com que uma linha em branco e uma linha de cruft sejam exibidas no console do Windows. No entanto, você pode se safar sem uma
#!
linha: na maioria dos sistemas, um dos intérpretes shell comuns acabará executando o script (o problema é que não é universalmente previsível qual intérprete será - depende, mas será não necessariamente ser idêntico ao shell que você usa para chamar o comando).Além dessa primeira linha complicada, havia algumas soluções realmente sem criatividade. A submissão vencedora por jimmy23013 consistiu em apenas duas linhas de infraestrutura curtas e fez uso do duplo papel do
:
personagem para implementar uma linha "silenciosa" em ambas as plataformas (como um não-op de fatosh
e amigos e como um rótulo marcador emcmd.exe
):Ele é possível fazer um script executado em sistemas POSIX, mesmo apesar CRLF linha-finais, mas para fazer isso para a maioria dos intérpretes você tem que acabar com todos os linha de sua seção POSIX (mesmo linhas em branco) com um caractere de comentário ou comentário.
Finalmente, aqui estão duas variantes de uma solução que desenvolvi com base nas informações de todos. Eles podem ser quase os melhores de todos os mundos, pois minimizam os danos causados pela falta
#!
e tornam a compatibilidade com CRLF ainda mais suave. São necessárias duas linhas de infraestrutura extras. Somente uma linha (padronizada) deve ser interpretada pelo imprevisível shell POSIX, e essa linha permite selecionar o shell para o restante do script (bash
no exemplo a seguir):Parte da beleza dessas soluções heredoc é que elas ainda são robustas para CRLF: desde que
<<:Z
chegue ao final da linha, o processador heredoc estará realmente procurando e encontrará o token:Z\r
Como uma reviravolta final, você pode se livrar desses comentários de fim de linha irritantes e ainda manter a robustez do CRLF, removendo os
\r
caracteres antes de passar as linhas para o shell. Isso coloca um pouco mais de fé no shell imprevisível (seria bom usar em{ tr -d \\r|bash;}
vez de,(tr -d \\r|bash)
mas colchetes são sintaxe somente do bash):Obviamente, essa abordagem sacrifica a capacidade de canalizar a entrada stdin no script.
fonte