Eseguire uno script di shell su OS X senza visualizzare una finestra terminale?


23

Sto cercando di impostare alcune scorciatoie da tastiera che aprono sessioni iTerm specifiche, cosa che sono stato in grado di fare con BetterTouchTool e un po 'di magia AppleScript. Il problema è che OS X insiste per aprire una finestra Terminale per qualsiasi script shell eseguito tramite la GUI (ovvero da Finder o come scorciatoia da tastiera da BetterTouchTool). La finestra del terminale non viene visualizzata se eseguo lo script direttamente da un altro terminale.

Una soluzione alternativa che ho trovato è stata quella di avvolgere lo script in una directory .app, che risolve il problema della finestra del terminale superfluo, ma presenta alcuni altri problemi (ad esempio OS X sembra trattare ogni finestra iTerm risultante come un'app separata, ingombrando il mio dock ). (EDIT: questo comportamento è stato effettivamente causato da un bug nel mio script, vedi sotto)

Ho anche provato ad assegnare l'app Terminale a un altro desktop virtuale nelle impostazioni di Spaces nel tentativo di spostarlo fuori dalla vista, ma poi passerà a quel desktop prima di eseguire lo script.

C'è un modo per disabilitare completamente questo comportamento? Ho già trovato l'impostazione nelle preferenze di Terminale per chiudere la finestra al termine dello script, ma è comunque fastidioso far apparire la finestra di Terminale per un secondo.


Scusa, non capisco bene. Cosa vuoi fare con quegli script di shell? Vuoi aprire iTerm attraverso uno script di shell? Stai parlando esclusivamente di Terminal.app o mescolando iTerm con "Terminale" nella tua domanda? Potresti forse pubblicare un esempio di ciò che stai cercando di eseguire?
slhck,

Ho impostato diverse sessioni iTerm per avviare una normale shell, aprire una console Rails, visualizzare il registro Rails ecc. Sto usando esclusivamente iTerm e Terminal viene aperto automaticamente da OS X per qualsiasi motivo sciocco. Comunque, ho trovato una soluzione per far funzionare correttamente l'approccio bundle (vedi domanda modificata).
toupeira,

Vedo! Bene, sarebbe fantastico se tu potessi rispondere alla tua stessa domanda (usando il pulsante qui sotto) e dirci cosa hai fatto o come hai risolto il problema. Forse pubblica alcuni esempi nella tua domanda, quindi aggiungi solo una breve risposta. In questo modo, se qualcuno inciampa sul tuo post, potrebbe imparare qualcosa da esso!
slhck,

Beh, non ho ancora una risposta per la vera domanda (cioè come evitare completamente il Terminale, senza dover usare un wrapper .app), quindi preferirei lasciarlo aperto nel caso qualcuno mi possa illuminare.
toupeira,

1
Sono ancora confuso. Lei non si desidera eseguire loro tramite un .app creato da Automator?
slhck,

Risposte:


21

Apri Automator , scegli Applicazione , aggiungi un'azione Esegui script shell e inserisci il comando Shell tra virgolette (se hai un file, puoi semplicemente trascinarlo e rilasciarlo).

Oltre a giocarci, ora puoi salvarlo (come app ovunque) e persino impostare l'icona .


Ho provato a eseguire un comando in questo modo da un'app a schermo intero, tuttavia lo ha sempre aperto in background. Ho dovuto mettere in background il comando nella shell in modo non bloccante aggiungendo un &e quindi chiamare un AppleScript per portare l'app (nel mio caso mplayer) in primo piano: 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,

Fantastico hack @mcb. Ma non capisco perché. Di solito vogliamo nascondere la finestra del terminale perché aprirà un'altra finestra, che è quella principale. Se hai bisogno della prima finestra del terminale di mplayer, suppongo che non ne apra un'altra e quindi perché dovresti nasconderlo in primo luogo?
Cregox,

Sto usando mplayerper riprodurre un video all'interno di una presentazione (in Skim). C'è un bug che il giocatore rimane in background se Skim è impostato su schermo intero, non sono sicuro, tuttavia, se questo bug è correlato solo a Skim o a tutte le app a schermo intero, quindi ho pensato di pubblicare la mia soluzione qui.
Lenar Hoyt,

6

Ecco un esempio veloce e sporco senza quasi nessuno sforzo (per un'app chiamata "myapp"):

  1. Crea una gerarchia di applicazioni parziali:

        mkdir -p ./myapp.app/Contents/MacOS
    
  2. Assicurati che la prima riga dello script abbia il percorso completo del programma necessario, ad es.

    #!/bin/bash
    
  3. Denominate lo script della shell "myapp" (senza virgolette, senza estensione), dategli le autorizzazioni di esecuzione e poi inseritelo nella sottodirectory MacOS. Per dargli le autorizzazioni di esecuzione:

    chmod ugo+x myapp
    
  4. Vai alla sottodirectory Contenuto e crea un file PkgInfo contenente la stringa: APPL ???? [nessun terminatore di riga alla fine della stringa!] Utilizzare l'utilità cat (1) per creare il file:

    cat > PkgInfo
    APPL????
    

    Dopo aver digitato la stringa (non premere return!), Inserisci due control-D, che chiuderanno
    il file senza terminatore di riga e torneranno al prompt della shell.)

  5. Fai doppio clic sulla nuova "app" dal Finder. Funzionerà senza finestra.


Non ha funzionato su 10.13.6, il messaggio di errore dice "Impossibile aprire l'applicazione" LoginSessionTimeLimit.app "perché non è supportato su questo tipo di Mac."
Douglas Held,

1
Ha funzionato in Mojave (10.14.3) per me. Mi è piaciuto molto questo approccio. Grazie.
loco.loop

Ha funzionato per me il 10.13.6. @Douglas Held prova a eseguire lo script "manualmente", ovvero dal Terminale. Probabilmente esce con errore quindi non funziona per te ...
marekful

Grande! Testato in Mojave 10.14.6
Nicola Mingotti il

4

Potresti voler provare Platypus , che crea applicazioni Mac OS X da script di shell e altri script interpretati.


3

Ecco una piccola soluzione, nel caso abbiate voglia di lanciatori di applicazioni come Alfred . Lo uso ogni giorno e ho acquistato il Powerpack , che consente di eseguire script di shell silenziosi.

inserisci qui la descrizione dell'immagine

Questi non apriranno un terminale durante l'esecuzione e possono essere associati a qualsiasi sequenza di parole chiave. Possono anche includere parametri e avere opzioni aggiuntive:

inserisci qui la descrizione dell'immagine

Lo uso per alcuni piccoli frammenti ed è molto flessibile.


Questo non è più disponibile in Alfred 2. Invece, crea uno "Esegui script" come mostrato in figura .
Dave Newton,

1

Se aggiungi la chiave LSUIElemente la imposti su 1nella Info.plisttua app, non creerà un'icona nel Dock.

Ecco la Info.plistmia piccola app di 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>

Grazie, ma questo non sembra avere alcun effetto. Ho anche provato a utilizzare touchil bundle per assicurarmi che fosse utilizzata la versione più recente. Ma comunque, non mi piace molto l'approccio bundle perché sembra che creerà sempre istanze di app separate
toupeira

Anche per me il tocco non ha aiutato (ho provato a spegnere LSUIElement), c'è qualche altro tipo di memorizzazione nella cache, ma la compressione e l'estrazione dell'applicazione ha aiutato. Perché non ti piace l'approccio in bundle? Inoltre puoi usare applecript ed eseguire do shell script "say 'arsti'", questo non aprirà la finestra del terminale.
tig

Ok, risulta che sono solo un idiota ;-) Non sono riuscito a trovare un modo affidabile per verificare se un'app è già in esecuzione con AppleScript, quindi ho usato un normale script bash che chiama pgrepe quindi passa il codice pertinente direttamente a osascript(l'interprete AppleScript). Il problema è che pgrepproviene da Homebrew e non è l'impostazione predefinita $PATH. Quindi il mio script ha sempre lanciato una nuova istanza iTerm, anche se era già in esecuzione. Dopo aver aggiunto l'intero percorso pgrepnello script, l'approccio del bundle sembra funzionare bene dopo tutto, quindi penso di essere felice per ora ;-)
toupeira

Combinando questa risposta con quella di @JeffB sopra e con una versione semplificata di Info.plist di @ tig (ho rimosso i tasti CFBundleExecutablee CFBundleIconFile), ho ottenuto che funzionasse perfettamente.
Dave Land

0

Ecco un po 'di soluzione:

Compilare un applecript che chiama uno script di shell :)

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

Il osacompilecompilerà il 'do shell script "XXX"'frammento di AppleScript. Lo script della shell è il XXX.

Fai attenzione al preventivo, lo script della shell deve essere citato correttamente per superare la shell che stai usando per compilarla ancora intatta.

Ma questo può essere eseguito da BetterTouchTool senza alcuna stranezza.


0

C'è un altro possibile allenamento. Proteggi lo script della shell in un flusso di lavoro dell'automatore. Richiamare il flusso di lavoro con launchd. Il codice è:

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

Questo non avvierà alcun programma né apparirà nella barra dei menu e sarà più silenzioso di un'app Platypus.

Un modo ancora migliore per eseguire script di shell è diretto in launchd.

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

eseguirà il comando in modo ultra silenzioso in background.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.