Ausführen eines Befehls in einem neuen Mac OS X Terminal-Fenster


89

Ich habe versucht herauszufinden, wie ein Bash-Befehl in einem neuen Max OS X Terminal.app-Fenster ausgeführt wird. Als Beispiel würde ich meinen Befehl in einem neuen Bash-Prozess ausführen:

bash -c "my command here"

Dadurch wird jedoch das vorhandene Terminalfenster wiederverwendet, anstatt ein neues zu erstellen. Ich möchte so etwas wie:

Terminal.app -c "my command here"

Aber das funktioniert natürlich nicht. Mir ist der Befehl "open -a Terminal.app" bekannt, aber ich sehe nicht, wie Argumente an das Terminal weitergeleitet werden sollen oder ob ich welche Argumente verwendet habe.


Sie können jederzeit Einstellungen öffnen, zur Registerkarte "Profile" wechseln, auf die Seite "Shell" gehen und dort den Startbefehl festlegen. Es läuft nur, wenn die Anwendung geöffnet ist, aber es funktioniert besser als die hackigen Alternativen!
Zane Helton

Siehe auch die gleiche Frage an Superuser superuser.com/q/174576/122841
Beetle

Antworten:


95

Eine Möglichkeit, wie ich es mir vorstellen kann, besteht darin, eine Befehlsdatei zu erstellen und wie folgt auszuführen:

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

oder Applescript verwenden:

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

obwohl Sie entweder viele doppelte Anführungszeichen vermeiden müssen oder keine einfachen Anführungszeichen verwenden können


Ich habe mich für die erste Methode entschieden. Es ist ziemlich hackig, aber es funktioniert und ich muss mir keine Sorgen machen, dass ich Anführungszeichen in meinem Befehl oder irgendetwas entkomme. Vielen Dank.
Walt D

3
Wenn der Befehl parametrisiert ausgeführt werden muss, möchten Sie möglicherweise die einfachen und doppelten Anführungszeichen austauschen. Sie müssen jedoch den Unterschied verstehen, um dies korrekt ausführen zu können. osascript -e "tell application \"Terminal\" to do script \"echo '$variable'\"'
Tripleee

weiß jemand, wie man das blöde übrig gebliebene Terminalfenster schließt?
Nicholas DiPiazza

Fügen Sie ; exitam Ende des Shell-Skripts Befehle hinzu, wie z do script "echo hello; exit". Sie müssen das Fenster noch separat schließen.
Tripleee

65

Teillösung:

Fügen Sie die gewünschten Dinge wie folgt in ein Shell-Skript ein

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

Und vergessen Sie nicht chmod +x file, es ausführbar zu machen. Dann kannst du

open -a Terminal.app scriptfile

und es wird in einem neuen Fenster ausgeführt. Fügen Sie basham Ende des Skripts ' ' hinzu, damit die neue Sitzung nicht beendet wird. (Obwohl Sie möglicherweise herausfinden müssen, wie die RC-Dateien und Sachen des Benutzers geladen werden ..)


7
Der Kontext des neu geöffneten Fensters scheint der Stammordner des Benutzers zu sein /Users/{username}. Gibt es eine Möglichkeit, den Kontextordner mit dem übergeordneten Terminalfenster, in dem er geöffnet wurde, identisch zu halten?
Johnny Oshika

> Obwohl Sie möglicherweise herausfinden müssen, wie die RC-Dateien und andere Dinge des Benutzers geladen werden sollen. Verwenden Sie dazu bash -l
Aivar

35

Ich habe versucht, dies für eine Weile zu tun. Hier ist ein Skript, das in dasselbe Arbeitsverzeichnis wechselt, den Befehl ausführt und das Terminalfenster schließt.

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

Sie mögen kein akzeptiertes Skript und lösen das aktuelle Verzeichnisproblem. Vielen Dank!
Marboni

Tolle Lösung; Es gibt jedoch so etwas wie tab 1 of window id 7433stdout in der Start- Shell aus. Um dies zu unterdrücken, platzieren Sie >/dev/null vor <<END .
mklement0

1
Dadurch wird das Terminalfenster nicht von Natur aus geschlossen. Es wird nur der Befehlsinterpreter beendet. Terminal.app muss so konfiguriert sein, dass das Fenster automatisch geschlossen wird oder der Befehlsinterpreter sauber beendet wird.
user66001

8

Falls es jemanden interessiert, hier ein Äquivalent für 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

Hier ist noch eine andere Sichtweise (auch mit 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' 

Siehe: Codesnippets.joyent.com/posts/show/1516


3

Ich habe eine Funktionsversion von Oskars Antwort erstellt. Diese kopiert auch die Umgebung und wechselt in das entsprechende Verzeichnis

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"
}

Sie können es so verwenden:

new_window my command here

oder

new_window ssh example.com

1
Die Leitung TMP_FILE="tmp.command"kann ein Problem sein, wenn Sie mehr als einen Prozess gleichzeitig starten. Ich würde vorschlagen, es durchTMP_FILE=$(mktemp "/tmp/command.XXXXXX")
duthen

2

Hier ist mein großartiges Skript, das bei Bedarf ein neues Terminalfenster erstellt und in das Verzeichnis wechselt, in dem sich der Finder befindet, wenn der Finder ganz vorne steht. Es verfügt über alle Maschinen, die Sie zum Ausführen von Befehlen benötigen.

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

Ein Kollege fragte mich, wie ich VIELE SSH-Sitzungen gleichzeitig eröffnen könne. Ich habe Cobbals Antwort verwendet, um dieses Skript zu schreiben:

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

Durch Aktualisieren der Liste der Befehle (es müssen keine SSH-Aufrufe sein) erhalten Sie für jeden ausgeführten Befehl ein zusätzliches geöffnetes Fenster. Das sleep 60am Ende ist da, um die .commandDateien zu behalten, während sie ausgeführt werden. Andernfalls wird die Shell zu schnell abgeschlossen und der Trap ausgeführt, um das temporäre Verzeichnis (erstellt von mktemp) zu löschen, bevor die gestarteten Sitzungen die Möglichkeit haben, die Dateien zu lesen.


0

Sie können die neue Befehlsfunktion von Terminal auch durch Drücken der Shift + ⌘ + NTastenkombination aufrufen . Der Befehl, den Sie in die Box eingeben, wird in einem neuen Terminalfenster ausgeführt.


Natürlich nützlich zu wissen, aber ich muss es programmatisch tun. Wenn mein Programm eine Befehlsdatei generiert und diese dann öffnet, ist dies eine vernünftige (wenn auch etwas hackige) Lösung.
Walt D

0

Ich nenne dieses Skript trun. Ich schlage vor, es in ein Verzeichnis in Ihrem ausführbaren Pfad zu legen. Stellen Sie sicher, dass es wie folgt ausführbar ist:

chmod +x ~/bin/trun

Anschließend können Sie Befehle in einem neuen Fenster ausführen, indem Sie einfach trun wie folgt hinzufügen:

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

Hier ist das Skript. Es macht einige ausgefallene Dinge wie das Übergeben Ihrer Argumente, das Ändern der Titelleiste, das Löschen des Bildschirms, um Unordnung beim Starten der Shell zu beseitigen, und das Entfernen der Datei, wenn dies erledigt ist. Durch die Verwendung einer eindeutigen Datei für jedes neue Fenster können mehrere Fenster gleichzeitig erstellt werden.

#!/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
Die falsche Verwendung von $*durchgehend zerstört alle nicht trivialen Zitate in der Eingabe. Du willst "$@"stattdessen.
Tripleee

Ich habe gesucht open -b com.apple.terminal. Danke
Ebru Yener
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.