Executar um script de shell no OS X sem que uma janela de terminal apareça?


23

Estou tentando configurar alguns atalhos de teclado que abrem sessões específicas do iTerm, o que pude fazer com o BetterTouchTool e um pouco da mágica do AppleScript. O problema é que o OS X insiste em abrir uma janela do Terminal para qualquer script de shell que você executa por meio da GUI (por exemplo, do Finder ou como um atalho de teclado do BetterTouchTool). A janela do terminal não aparece se eu executar o script diretamente de outro terminal.

Uma solução alternativa que encontrei foi agrupar o script em um diretório .app, que resolve o problema da janela supérflua do terminal, mas tem outros problemas (por exemplo, o OS X parece tratar cada janela resultante do iTerm como um aplicativo separado, sobrecarregando meu dock. ) (EDIT: este comportamento foi realmente causado por um bug no meu script, veja abaixo)

Também tentei atribuir o aplicativo Terminal a outra área de trabalho virtual nas configurações do Spaces, na tentativa de afastá-lo da vista, mas, em seguida, ele mudaria primeiro para essa área de trabalho antes de executar o script.

Existe uma maneira de desativar esse comportamento completamente? Eu já encontrei a configuração nas preferências do Terminal para fechar a janela após a conclusão do script, mas ainda é irritante fazer a janela do Terminal aparecer por um segundo.


Desculpe, eu não entendo direito. O que você quer fazer com esses scripts de shell? Deseja abrir o iTerm através de um script de shell? Você está falando exclusivamente sobre o Terminal.app ou misturando o iTerm com o "Terminal" na sua pergunta? Você poderia postar um exemplo do que você está tentando executar?
slhck

Configurei várias sessões do iTerm para iniciar um shell normal, abrir um console do Rails, exibir o log do Rails etc. Estou usando o iTerm exclusivamente e o Terminal é aberto automaticamente pelo OS X por qualquer motivo bobo. De qualquer maneira, encontrei uma solução para fazer com que a abordagem de pacote funcionasse corretamente (consulte a pergunta editada).
Toupeira

Eu vejo! Bem, seria incrível se você pudesse responder sua própria pergunta (usando o botão abaixo) e nos contar o que fez ou como resolveu o problema. Talvez publique alguns exemplos em sua pergunta e adicione uma breve resposta. Dessa forma, se alguém tropeçar na sua postagem, poderá aprender algo com ela!
slhck

Bem, eu ainda não tenho uma resposta para a pergunta real (ou seja, como evitar o Terminal completamente, sem ter que usar um invólucro .app), então prefiro deixá-lo aberto caso alguém possa me esclarecer.
Toupeira 22/11

1
Eu ainda estou confuso. Você não deseja executá-los por meio de um .app criado pelo Automator?
slhck

Respostas:


21

Abra o Automator , escolha Aplicativo , adicione uma ação Executar Script do Shell e insira seu comando do Shell entre aspas (se você tiver um arquivo, basta arrastar e soltar).

Além de reproduzi-lo, agora você pode salvá- lo (como um aplicativo em qualquer lugar) e até definir o ícone .


Tentei executar um comando dessa maneira em um aplicativo de tela cheia, no entanto, ele sempre era aberto em segundo plano. Eu tinha de fundo o comando no shell de uma forma non-blocking, acrescentando um &e depois chamar um AppleScript para trazer o aplicativo (no meu caso mplayer) para a frente: mplayer myvideo.avi &; osascript -e 'tell application "System Events" to set frontmost of the first process whose displayed name is "mplayer" to true'
Lenar Hoyt

Legal hack @mcb. Mas eu não entendo o porquê. Normalmente, queremos ocultar a janela do terminal porque ela abrirá outra janela, que é a principal. Se você precisa da primeira janela do terminal do mplayer, suponho que ela não abra outra e, então, por que você deseja ocultá-la?
Cregox

Estou usando mplayerpara reproduzir um vídeo em uma apresentação de slides (no Skim). Há um bug que o jogador permanece em segundo plano se o Skim estiver definido como tela cheia, não tenho certeza, se esse bug está relacionado apenas ao Skim ou a todos os aplicativos em tela cheia, então imaginei que postaria minha solução aqui.
Lenar Hoyt

6

Aqui está um exemplo rápido e sujo, quase sem esforço (para um aplicativo chamado "myapp"):

  1. Faça uma hierarquia parcial de aplicativos:

        mkdir -p ./myapp.app/Contents/MacOS
    
  2. Verifique se a primeira linha do seu script possui o caminho completo para o programa necessário, por exemplo,

    #!/bin/bash
    
  3. Nomeie seu script de shell como "myapp" (sem aspas, sem extensão), conceda permissões de execução e coloque-o no subdiretório MacOS. Para conceder permissões de execução:

    chmod ugo+x myapp
    
  4. Vá para o subdiretório Conteúdo e crie um arquivo PkgInfo contendo a sequência: APPL ???? [sem terminador de linha no final da string!] Use o utilitário cat (1) para criar o arquivo:

    cat > PkgInfo
    APPL????
    

    Depois de digitar a string (não pressione return!), Digite dois control-D's, que fecharão
    o arquivo sem terminador de linha e retornará ao prompt do shell.)

  5. Clique duas vezes no seu novo "aplicativo" no localizador. Ele será executado sem janela.


Não funcionou na versão 10.13.6, a mensagem de erro diz "Não é possível abrir o aplicativo" LoginSessionTimeLimit.app "porque ele não é suportado neste tipo de Mac".
Douglas Held

1
Trabalhou no Mojave (10.14.3) para mim. Eu realmente gostei dessa abordagem. Obrigado.
loco.loop 28/02

Trabalhou para mim em 10.13.6. @Douglas Held tente executar seu script "manualmente", ou seja, no Terminal. Provavelmente ele sai com erro, portanto, não está funcionando para você ...
marekful 18/04

Ótimo! Testado trabalhando no Mojave 10.14.6
Nicola Mingotti 13/12

4

Convém verificar o Platypus , que cria aplicativos Mac OS X a partir de scripts de shell e outros scripts interpretados.


3

Aqui está uma pequena solução alternativa, caso você goste de iniciantes de aplicativos como Alfred . Uso-o todos os dias e comprei o Powerpack , que permite executar scripts shell silenciosos.

insira a descrição da imagem aqui

Eles não abrirão um terminal durante a execução e podem ser vinculados a qualquer sequência de palavras-chave. Eles podem até incluir parâmetros e ter opções adicionais:

insira a descrição da imagem aqui

Eu uso isso para alguns pequenos trechos, e é muito flexível.


Isso não está mais disponível no Alfred 2. Em vez disso, crie um "Run Script" como mostrado na figura .
Dave Newton

1

Se você adicionar uma chave LSUIElemente configurá-la como 1no Info.plistseu aplicativo, ele não criará um ícone no Dock.

Aqui está o Info.plistmeu pequeno aplicativo de script de shell:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleExecutable</key>
    <string>launch</string>
    <key>CFBundleIconFile</key>
    <string>launch</string>
    <key>LSUIElement</key>
    <string>1</string>
</dict>
</plist>

Obrigado, mas isso não parece ter efeito. Eu também tentei toucho pacote para garantir que a versão mais recente fosse usada. Mas de qualquer maneira, eu realmente não gosto a abordagem do cabaz porque parece que sempre vai criar instâncias de aplicativos separados
toupeira

Para mim, o toque também não ajudou (tentei desativar o LSUIElement); existe algum outro tipo de cache, mas o aplicativo de compactação e extração ajudou. Por que você não gosta de abordagem de pacotes? Além disso, você pode usar o AppleScript e apenas executar do shell script "say 'arsti'", isso não abrirá a janela do terminal.
tig

Ok, parece que sou apenas um idiota ;-) Não consegui encontrar uma maneira confiável de verificar se um aplicativo já está sendo executado com AppleScript, então usei um script bash normal que chama pgrepe depois passa o código relevante diretamente para osascript(o intérprete AppleScript). O problema é que pgrepveio do Homebrew e não está no padrão $PATH. Portanto, meu script sempre lançava uma nova instância do iTerm, mesmo que já estivesse em execução. Depois de adicionar o caminho completo para pgrepno script a abordagem do cabaz parece funcionar bem depois de tudo, então eu acho que eu estou feliz por agora ;-)
toupeira

Combinando esta resposta com a de @JeffB acima, e com uma versão simplificada do Info.plist do @ tig (removi as teclas CFBundleExecutablee CFBundleIconFile), consegui que funcionasse perfeitamente.
Dave Land

0

Aqui está um pouco de uma solução alternativa:

Compile um AppleScript que chama um shell script :)

osacompile -e 'do shell script "cd ~; echo aaa > temp.txt"' -o ~/name_of_script.scpt

O osacompilecompilará o 'do shell script "XXX"'snippet de AppleScript. Seu script de shell é o XXX.

Cuidado com as citações, o script do shell deve ser citado corretamente para passar pelo shell que você está usando para compilá-lo ainda intacto.

Mas isso pode ser executado a partir do BetterTouchTool sem qualquer estranheza.


0

Há outro treino possível. Proteja seu script de shell em um fluxo de trabalho de automação. Invoque o fluxo de trabalho com o launchd. O código é:

/usr/bin/automator /path/to/the/file.workflow

Isso não iniciará nenhum programa nem aparecerá na barra de menus e será mais silencioso que um aplicativo Platypus.

Uma maneira ainda melhor de executar scripts de shell é direta no launchd.

/bin/bash /path/to/shellScript.command

executará o comando ultra silenciosamente em segundo plano.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.