Exécuter un script shell sur OS X sans qu'une fenêtre de terminal apparaisse?

23

J'essaie de configurer quelques raccourcis clavier qui ouvrent des sessions iTerm spécifiques, ce que j'ai pu faire avec BetterTouchTool et un peu de magie AppleScript. Le problème est qu'OS X insiste pour ouvrir une fenêtre de terminal pour tout script shell que vous exécutez via l'interface graphique (c'est-à-dire à partir du Finder ou comme raccourci clavier de BetterTouchTool). La fenêtre du terminal n'apparaît pas si j'exécute le script directement à partir d'un autre terminal.

Une solution de contournement que j'ai trouvée consistait à envelopper le script dans un répertoire .app, ce qui résout le problème de la fenêtre de terminal superflue, mais a d'autres problèmes (par exemple, OS X semble traiter chaque fenêtre iTerm résultante comme une application distincte, encombrant mon dock ). (EDIT: ce comportement a été causé par un bug dans mon script, voir ci-dessous)

J'ai également essayé d'attribuer l'application Terminal à un autre bureau virtuel dans les paramètres des espaces pour tenter de la déplacer hors de vue, mais elle passera d'abord sur ce bureau avant d'exécuter le script.

Existe-t-il un moyen de désactiver complètement ce comportement? J'ai déjà trouvé le paramètre dans les préférences du terminal pour fermer la fenêtre une fois le script terminé, mais c'est toujours ennuyeux de voir la fenêtre du terminal s'afficher pendant une seconde.

toupeira
la source
Désolé, je ne comprends pas très bien. Que voulez-vous faire avec ces scripts shell? Voulez-vous ouvrir iTerm via un script shell? Parlez-vous exclusivement de Terminal.app ou de mélanger iTerm avec "Terminal" dans votre question? Pourriez-vous peut-être publier un exemple de ce que vous essayez d'exécuter?
slhck
J'ai configuré plusieurs sessions iTerm pour lancer un shell normal, ouvrir une console Rails, afficher le journal Rails, etc. J'utilise exclusivement iTerm et Terminal est ouvert automatiquement par OS X pour une raison stupide. Mais de toute façon, j'ai trouvé une solution pour que l'approche bundle fonctionne correctement (voir question éditée).
toupeira
Je vois! Eh bien, ce serait génial si vous pouviez répondre à votre propre question (en utilisant le bouton ci-dessous) et nous dire ce que vous avez fait ou comment vous avez résolu le problème. Peut-être postez quelques exemples dans votre question, puis ajoutez simplement une brève réponse. De cette façon, si quelqu'un tombe sur votre message, il pourrait en tirer des leçons!
slhck
Eh bien, je n'ai toujours pas de réponse à la question réelle (c'est-à-dire comment éviter complètement le terminal, sans avoir à utiliser un wrapper .app), donc je préfère le laisser ouvert au cas où quelqu'un pourrait m'éclairer.
toupeira
1
Je suis encore confus. Vous ne voulez pas les exécuter via un .app créé par Automator?
slhck

Réponses:

21

Ouvrez Automator , choisissez Application , ajoutez une action Exécuter le script Shell et placez votre commande Shell entre guillemets (si vous avez un fichier, vous pouvez simplement le faire glisser et le déposer).

Outre la lecture, vous pouvez maintenant l' enregistrer (en tant qu'application n'importe où) et même définir l'icône .

cregox
la source
J'ai essayé d'exécuter une commande de cette façon à partir d'une application en plein écran, mais elle l'ouvrait toujours en arrière-plan. J'ai dû définir la commande dans le shell de manière non bloquante en ajoutant un &, puis appeler un AppleScript pour amener l'application (dans mon cas mplayer) au premier plan: 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
Cool hack @mcb. Mais je ne comprends pas pourquoi. Habituellement, nous voulons masquer la fenêtre du terminal car cela ouvrira une autre fenêtre, qui est la principale. Si vous avez besoin de la première fenêtre de terminal de mplayer, je suppose qu'elle n'en ouvre pas une autre et alors pourquoi voudriez-vous la cacher en premier lieu?
cregox
J'utilise mplayerpour lire une vidéo à partir d'un diaporama (dans Skim). Il y a un bug que le joueur reste en arrière-plan si Skim est réglé sur plein écran, je ne suis pas sûr cependant, si ce bug est uniquement lié à Skim ou à toutes les applications en plein écran, j'ai donc pensé publier ma solution ici.
Lenar Hoyt
6

Voici un exemple rapide et sale avec presque aucun effort (pour une application nommée "myapp"):

  1. Faites une hiérarchie partielle des applications:

        mkdir -p ./myapp.app/Contents/MacOS
    
  2. Assurez-vous que la première ligne de votre script a le chemin d'accès complet au programme requis, par exemple,

    #!/bin/bash
    
  3. Nommez votre script shell "myapp" (sans guillemets, sans extension), donnez-lui des autorisations d'exécution, puis placez-le dans le sous-répertoire MacOS. Pour lui donner des autorisations d'exécution:

    chmod ugo+x myapp
    
  4. Accédez au sous-répertoire Contents et créez un fichier PkgInfo contenant la chaîne: APPL ???? [pas de terminaison de ligne à la fin de la chaîne!] Utilisez l'utilitaire cat (1) pour créer le fichier:

    cat > PkgInfo
    APPL????
    

    Après avoir tapé la chaîne (n'appuyez pas sur la touche retour!), Entrez deux contrôles-D, qui fermeront
    le fichier sans terminateur de ligne et vous renverront à l'invite du shell.)

  5. Double-cliquez sur votre nouvelle "application" dans le Finder. Il fonctionnera sans fenêtre.

JeffB
la source
N'a pas fonctionné sur 10.13.6, le message d'erreur indique "Vous ne pouvez pas ouvrir l'application" LoginSessionTimeLimit.app "car elle n'est pas prise en charge sur ce type de Mac."
Douglas tenue
1
A travaillé à Mojave (10.14.3) pour moi. J'ai vraiment aimé cette approche. Merci.
loco.loop
A travaillé pour moi le 10.13.6. @Douglas Held a essayé d'exécuter votre script "manuellement", c'est-à-dire depuis le terminal. Probablement, il se termine avec une erreur, donc cela ne fonctionne pas pour vous ...
marekful
Génial! Testé en travaillant à Mojave 10.14.6
Nicola Mingotti
4

Vous voudrez peut-être consulter Platypus , qui crée des applications Mac OS X à partir de scripts shell et d'autres scripts interprétés.

svth
la source
3

Voici une petite solution de contournement, au cas où vous auriez envie de lanceurs d'applications comme Alfred . Je l'utilise tous les jours et j'ai acheté le Powerpack , qui vous permet d'exécuter des scripts shell silencieux.

entrez la description de l'image ici

Ceux-ci n'ouvriront pas de terminal lors de l'exécution et peuvent être liés à n'importe quelle séquence de mots clés. Ils peuvent même inclure des paramètres et avoir des options supplémentaires:

entrez la description de l'image ici

J'utilise cela pour quelques petits extraits, et c'est très flexible.

slhck
la source
Ce n'est plus disponible sous Alfred 2. Au lieu de cela, créez un "Run Script" comme indiqué dans l'image .
Dave Newton
1

Si vous ajoutez une clé LSUIElementet la définissez sur 1dans Info.plistvotre application, elle ne créera pas d'icône dans le Dock.

Voici Info.plistma petite application de script 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>
tig
la source
Merci, mais cela ne semble pas avoir d'effet. J'ai également essayé touchle bundle pour m'assurer que la dernière version était utilisée. Mais de toute façon, je n'aime pas vraiment l'approche groupée car il semble qu'elle créera toujours des instances d'application distinctes
toupeira
Pour moi, le toucher n'a pas aidé non plus (j'ai essayé de désactiver LSUIElement), il existe une autre sorte de mise en cache, mais la compression et l'extraction de l'application ont aidé. Pourquoi n'aimez-vous pas l'approche groupée? Vous pouvez également utiliser applescript et simplement exécuter do shell script "say 'arsti'", cela n'ouvrira pas la fenêtre du terminal.
tig
D'accord, il se trouve que je suis juste un idiot ;-) Je n'ai pas pu trouver un moyen fiable de vérifier si une application est déjà en cours d'exécution avec AppleScript, j'ai donc utilisé un script bash normal qui appelle pgrep, puis passe le code pertinent directement à osascript(l'interpréteur AppleScript). Le problème pgrepvient de Homebrew et n'est pas par défaut $PATH. Mon script a donc toujours lancé une nouvelle instance iTerm, même si elle était déjà en cours d'exécution. Après avoir ajouté le chemin complet pgrepdans le script, l'approche du bundle semble bien fonctionner après tout, donc je pense que je suis content pour l'instant ;-)
toupeira
En combinant cette réponse avec celle de @JeffB ci-dessus, et avec une version simplifiée d'Info.plist de @ tig (j'ai supprimé les touches CFBundleExecutableet CFBundleIconFile), j'ai réussi à ce que cela fonctionne parfaitement.
Dave Land
0

Voici un petit contournement:

Compilez un applescript qui appelle un script shell :)

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

Le osacompilecompilera l' 'do shell script "XXX"'extrait de code Apple. Votre script shell est le XXX.

Méfiez-vous des citations, le script shell doit être cité correctement pour dépasser le shell que vous utilisez pour le compiler toujours intact.

Mais cela peut être exécuté à partir de BetterTouchTool sans aucune folie.

kenny
la source
0

Il existe un autre entraînement possible. Protégez votre script shell dans un workflow d'automatisme. Appelez le workflow avec launchd. Le code est:

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

Cela ne lancera aucun programme ni n'apparaîtra dans la barre de menu et son chemin sera plus silencieux qu'une application Platypus.

Une manière encore meilleure d'exécuter des scripts shell est directe dans launchd.

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

exécutera la commande ultra silencieusement en arrière-plan.

Atalantia
la source