Exécution d'une commande dans une nouvelle fenêtre de terminal Mac OS X


89

J'ai essayé de comprendre comment exécuter une commande bash dans une nouvelle fenêtre Max OS X Terminal.app. À titre d'exemple, voici comment j'exécuterais ma commande dans un nouveau processus bash:

bash -c "my command here"

Mais cela réutilise la fenêtre de terminal existante au lieu d'en créer une nouvelle. Je veux quelque chose comme:

Terminal.app -c "my command here"

Mais bien sûr, cela ne fonctionne pas. Je connais la commande "open -a Terminal.app", mais je ne vois pas comment transmettre des arguments au terminal, ni même si j'ai fait quels arguments utiliser.


Vous pouvez toujours ouvrir les préférences, aller dans l'onglet "Profils", aller dans la page "Shell" et y définir la commande de démarrage. Il ne fonctionne que lorsque l'application est ouverte, mais cela fonctionne mieux que les alternatives hacky!
Zane Helton

Voir également la même question sur superuser superuser.com/q/174576/122841
Beetle

Réponses:


95

une façon dont je peux penser à le faire par le haut de ma tête est de créer un fichier .command et de l'exécuter comme ceci:

echo echo hello > sayhi.command; chmod +x sayhi.command; open sayhi.command

ou utilisez applescript:

osascript -e 'tell application "Terminal" to do script "echo hello"'

bien que vous deviez soit échapper à un grand nombre de guillemets doubles, soit ne pas pouvoir utiliser de guillemets simples


J'ai choisi la première méthode. C'est assez hack-ish, mais cela fonctionne et je n'ai pas à me soucier d'échapper des guillemets dans ma commande ou quoi que ce soit. Merci.
Walt D

3
Si la commande doit être paramétrée, vous voudrez peut-être échanger les guillemets simples et doubles; mais vous devez comprendre la différence afin de pouvoir le faire correctement. osascript -e "tell application \"Terminal\" to do script \"echo '$variable'\"'
tripleee

quelqu'un sait comment fermer la fenêtre du terminal gauche stupide?
Nicholas DiPiazza

Ajoutez ; exità la fin des commandes de script shell, comme do script "echo hello; exit". Vous devez toujours fermer la fenêtre séparément.
tripleee

65

Solution partielle:

Mettez les choses que vous voulez faire dans un script shell, comme ceci

#!/bin/bash
ls
echo "yey!"

Et n'oubliez pas de ' chmod +x file' le rendre exécutable. Ensuite vous pouvez

open -a Terminal.app scriptfile

et il fonctionnera dans une nouvelle fenêtre. Ajoutez ' bash' à la fin du script pour empêcher la nouvelle session de se terminer. (Bien que vous deviez peut-être trouver comment charger les fichiers rc des utilisateurs et d'autres choses ..)


7
Le contexte de la fenêtre nouvellement ouverte semble être le dossier racine de l'utilisateur /Users/{username}. Existe-t-il un moyen de conserver le dossier de contexte identique à la fenêtre du terminal parent qui l'a ouvert?
Johnny Oshika

> Bien que vous deviez peut-être trouver comment charger les fichiers rc des utilisateurs et d'autres choses .. utilisez bash -l pour cela
Aivar

35

J'essaye de faire ça depuis un moment. Voici un script qui passe au même répertoire de travail, exécute la commande et ferme la fenêtre du terminal.

#!/bin/sh 
osascript <<END 
tell application "Terminal"
    do script "cd \"`pwd`\";$1;exit"
end tell
END

Je n'aime pas le script accepté, votre seul problème de répertoire actuel. Merci!
Marboni

Excellente solution; il produit cependant quelque chose comme tab 1 of window id 7433stdout dans le shell de lancement . Pour supprimer cela, placez-le >/dev/null avant <<END .
mklement0

1
Cela ne ferme pas intrinsèquement la fenêtre du terminal. Il quitte simplement l'interpréteur de commandes. Terminal.app doit être configuré pour fermer la fenêtre automatiquement, ou à la sortie propre de l'interpréteur de commandes.
user66001

8

Au cas où quelqu'un se soucierait, voici un équivalent pour iTerm:

#!/bin/sh
osascript <<END
tell application "iTerm"
 tell the first terminal
  launch session "Default Session"
  tell the last session
   write text "cd \"`pwd`\";$1;exit"
  end tell
 end tell
end tell
END

3

Voici encore une autre version (en utilisant également AppleScript):

function newincmd() { 
   declare args 
   # escape single & double quotes 
   args="${@//\'/\'}" 
   args="${args//\"/\\\"}" 
   printf "%s" "${args}" | /usr/bin/pbcopy 
   #printf "%q" "${args}" | /usr/bin/pbcopy 
   /usr/bin/open -a Terminal 
   /usr/bin/osascript -e 'tell application "Terminal" to do script with command "/usr/bin/clear; eval \"$(/usr/bin/pbpaste)\""' 
   return 0 
} 

newincmd ls 

newincmd echo "hello \" world" 
newincmd echo $'hello \' world' 

voir: codesnippets.joyent.com/posts/show/1516


3

J'ai fait une version fonctionnelle de la réponse d'Oscar, celle-ci copie également l'environnement et les modifications dans le répertoire approprié

function new_window {
    TMP_FILE=$(mktemp "/tmp/command.XXXXXX")
    echo "#!/usr/bin/env bash" > $TMP_FILE

    # Copy over environment (including functions), but filter out readonly stuff
    set | grep -v "\(BASH_VERSINFO\|EUID\|PPID\|SHELLOPTS\|UID\)" >> $TMP_FILE

    # Copy over exported envrionment
    export -p >> $TMP_FILE

    # Change to directory
    echo "cd $(pwd)" >> $TMP_FILE

    # Copy over target command line
    echo "$@" >> $TMP_FILE

    chmod +x "$TMP_FILE"
    open -b com.apple.terminal "$TMP_FILE"

    sleep .1 # Wait for terminal to start
    rm "$TMP_FILE"
}

Vous pouvez l'utiliser comme ceci:

new_window my command here

ou

new_window ssh example.com

1
La ligne TMP_FILE="tmp.command"peut poser un problème si vous démarrez plusieurs processus simultanément. Je suggérerais de le remplacer parTMP_FILE=$(mktemp "/tmp/command.XXXXXX")
duthen

2

Voici mon script génial, il crée une nouvelle fenêtre de terminal si nécessaire et bascule vers le répertoire dans lequel se trouve Finder si Finder est au premier plan. Il possède toutes les machines dont vous avez besoin pour exécuter des commandes.

on run
    -- Figure out if we want to do the cd (doIt)
    -- Figure out what the path is and quote it (myPath)
    try
        tell application "Finder" to set doIt to frontmost
        set myPath to finder_path()
        if myPath is equal to "" then
            set doIt to false
        else
            set myPath to quote_for_bash(myPath)
        end if
    on error
        set doIt to false
    end try

    -- Figure out if we need to open a window
    -- If Terminal was not running, one will be opened automatically
    tell application "System Events" to set isRunning to (exists process "Terminal")

    tell application "Terminal"
        -- Open a new window
        if isRunning then do script ""
        activate
        -- cd to the path
        if doIt then
            -- We need to delay, terminal ignores the second do script otherwise
            delay 0.3
            do script " cd " & myPath in front window
        end if
    end tell
end run

on finder_path()
    try
        tell application "Finder" to set the source_folder to (folder of the front window) as alias
        set thePath to (POSIX path of the source_folder as string)
    on error -- no open folder windows
        set thePath to ""
    end try

    return thePath
end finder_path

-- This simply quotes all occurrences of ' and puts the whole thing between 's
on quote_for_bash(theString)
    set oldDelims to AppleScript's text item delimiters
    set AppleScript's text item delimiters to "'"
    set the parsedList to every text item of theString
    set AppleScript's text item delimiters to "'\\''"
    set theString to the parsedList as string
    set AppleScript's text item delimiters to oldDelims
    return "'" & theString & "'"
end quote_for_bash

1

Un collègue m'a demandé comment ouvrir BEAUCOUP de sessions ssh à la fois. J'ai utilisé la réponse de Cobbal pour écrire ce script:

tmpdir=$( mktemp -d )
trap '$DEBUG rm -rf $tmpdir ' EXIT
index=1

{
cat <<COMMANDS
ssh user1@host1
ssh user2@host2
COMMANDS
} | while read command
do 
  COMMAND_FILE=$tmpdir/$index.command
  index=$(( index + 1 ))
  echo $command > $COMMAND_FILE
  chmod +x  $COMMAND_FILE
  open $COMMAND_FILE
done
sleep 60

En mettant à jour la liste des commandes (elles ne doivent pas nécessairement être des invocations ssh), vous obtiendrez une fenêtre ouverte supplémentaire pour chaque commande exécutée. Le sleep 60à la fin est là pour conserver les .commandfichiers pendant leur exécution. Sinon, le shell se termine trop rapidement, exécutant le trap pour supprimer le répertoire temporaire (créé par mktemp) avant que les sessions lancées aient l'occasion de lire les fichiers.


0

Vous pouvez également appeler la nouvelle fonction de commande de Terminal en appuyant sur la Shift + ⌘ + Ncombinaison de touches. La commande que vous mettez dans la boîte sera exécutée dans une nouvelle fenêtre de terminal.


Bien sûr utile à savoir, mais je dois le faire par programme. Demander à mon programme de générer un fichier .command puis de l'ouvrir est une solution raisonnable (même si elle est un peu piratée).
Walt D

0

J'appelle ce script trun. Je suggère de le mettre dans un répertoire dans votre chemin exécutable. Assurez-vous qu'il est exécutable comme ceci:

chmod +x ~/bin/trun

Ensuite, vous pouvez exécuter des commandes dans une nouvelle fenêtre en ajoutant simplement trun avant elles, comme ceci:

trun tail -f /var/log/system.log

Voici le script. Il fait des choses fantaisistes comme passer vos arguments, changer la barre de titre, effacer l'écran pour supprimer l'encombrement du démarrage du shell, supprimer son fichier une fois terminé. En utilisant un fichier unique pour chaque nouvelle fenêtre, il peut être utilisé pour créer plusieurs fenêtres en même temps.

#!/bin/bash
# make this file executable with chmod +x trun
# create a unique file in /tmp
trun_cmd=`mktemp`
# make it cd back to where we are now
echo "cd `pwd`" >$trun_cmd
# make the title bar contain the command being run
echo 'echo -n -e "\033]0;'$*'\007"' >>$trun_cmd
# clear window
echo clear >>$trun_cmd
# the shell command to execute
echo $* >>$trun_cmd
# make the command remove itself
echo rm $trun_cmd >>$trun_cmd
# make the file executable
chmod +x $trun_cmd

# open it in Terminal to run it in a new Terminal window
open -b com.apple.terminal $trun_cmd

1
L'utilisation incorrecte de $*tout au long de la ligne détruit toute citation non triviale dans l'entrée. Vous voulez à la "$@"place.
tripleee

Je cherchais open -b com.apple.terminal. Merci
Ebru Yener
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.