OS X Terminal.app: Wie starte ich eine neue Registerkarte im selben Verzeichnis wie die aktuelle Registerkarte?

24

Ich muss häufig eine neue Registerkarte im selben Verzeichnis wie meine aktuelle Registerkarte öffnen, um etwas anderes zu tun, während meine aktuelle Registerkarte von einem langen Prozess belegt ist. Wenn Sie jedoch eine neue Registerkarte erstellen, beginnt Terminal.app standardmäßig mit ~ /. Irgendeine Idee, wie man es automatisch zum Springen bringt?

Riobard
quelle
Vielen Dank für viele schnelle Antworten! Es ist in Ordnung, einen neuen Tab durch Aufrufen eines Skripts zu starten, aber ich habe mich gefragt, ob es eine andere Möglichkeit gibt, da ich kein Skript ausführen kann, wenn bereits ein Programm ausgeführt wird und den aktuellen Tab belegt: |
Riobard

Antworten:

10

In OS X 10.7 (Lion) unterstützt Terminal.app dies nativ: New Windows/Tabs open in: Same working directory

Alistair A. Israel
quelle
Es ist schade, dass Apple keine Backports ausführt. Ich würde dieses Feature gerne in Snow Leopard sehen.
Wander Nauta
4
Ich habe es eingestellt, aber es funktioniert nicht für mich. Das Einstellungsfenster sagt etwas über das Aktivieren von Escape-Sequenzen aus, bevor dies funktionieren kann.
Ram on Rails
2

Man muss sehr vorsichtig sein, wenn man Saiten durch verschiedene Umgebungen führt.

Ich führe 10.4 aus, daher öffnet mein 'tfork'-Skript stattdessen immer ein neues Fenster. Es sollte einfach sein, es an die Verwendung eines Tabs anzupassen:

#!/bin/sh

# source: http://www.pycs.net/bob/weblog/2004/02/23.html#P49
# Rewritten to use osascript args -> run handler args.
# Added ability to pass additional initial command and args to new shell.
#    Bug: Non ASCII characters are unreliable on Tiger.
#         Tiger's osascript seems to expect args to be encoded in
#         the system's primary encoding (e.g. MacRoman).
#         Once in AppleScript, they are handled OK. Terminal sends them
#         back to the shell as UTF-8.

test $# -eq 0 && set -- : # default command if none given
osascript - "$(pwd)" "$@" <<\EOF
on run args
  set dir to quoted form of (first item of args)
  set cmd_strs to {}
  repeat with cmd_str in rest of args
    set end of cmd_strs to quoted form of cmd_str
  end
  set text item delimiters to " "
  set cmd to cmd_strs as Unicode text
  tell app "Terminal" to do script "cd " & dir & " && " & cmd
end
EOF

Beispiel: tfork git log -p ..FETCH_HEAD


Änderung: cwd eines bereits laufenden Prozesses, der eine Terminal- Registerkarte belegt

Die Vorstellung, dass „das aktuelle Verzeichnis des Programms die aktuelle Registerkarte belegt“, ist nicht so offensichtlich, wie man es erwarten würde.

Jede Registerkarte " Terminal" verfügt über ein einzelnes tty-Gerät, das von den von ihr ausgeführten Prozessen verwendet wird (anfangs eine Shell; danach, unabhängig davon, welche Shell gestartet wird).

Jedes (normale) Terminal- Tty hat eine einzelne Vordergrund-Prozessgruppe, die man als das Tty "besetzend" betrachten könnte.

Jede Prozessgruppe kann mehrere Prozesse enthalten.

Jeder Prozess kann sein eigenes aktuelles Arbeitsverzeichnis (cwd) haben (einige Umgebungen geben jedem Thread ein eigenes cwd oder cwd-Äquivalent, aber das werden wir ignorieren).

Die vorstehenden Tatsachen legen eine Art Spur fest, die von tty bis cwd: tty -> Vordergrundprozessgruppe -> Prozesse der Vordergrundprozessgruppe -> cwds.

Der erste Teil (von tty bis zum Vordergrundprozess) des Problems kann mit der Ausgabe von ps gelöst werden :

ps -o tty,pid,tpgid,pgid,state,command | awk 'BEGIN{t=ARGV[1];ARGC=1} $1==t && $3==$4 {print $2}' ttyp6

(wobei "ttyp6" der Name der gewünschten Menge ist)

Die Zuordnung von process (PID) zu cwd kann mit lsof erfolgen :

lsof -F 0n -a -p 2515,2516 -d cwd

(wobei "2515,2516" eine durch Kommas getrennte Liste der interessierenden Prozesse ist)

Unter Tiger sehe ich jedoch keine direkte Möglichkeit, den tty-Gerätenamen eines bestimmten Terminalfensters abzurufen. Es gibt eine schrecklich hässliche Art, den Namen in Tiger zu finden. Vielleicht kann Leopard oder Snow Leopard es besser machen.

Ich habe alles in einem AppleScript wie folgt zusammengefasst:

on run
    (* Find the tty. *)
    -- This is ugly. But is seems to work on Tiger. Maybe newer releases can do better.
    tell application "Terminal"
        set w to window 1
        tell w
            set origName to name
            set title displays device name to not title displays device name
            set newName to name
            set title displays device name to not title displays device name
        end tell
    end tell
    set tty to extractTTY(origName, newName)
    if tty is "" then
        display dialog "Could not find the tty for of the current Terminal window." buttons "Cancel" cancel button "Cancel" default button "Cancel"
    end if

    (* Find the PIDs of the processes in the foreground process group on that tty. *)
    set pids to paragraphs of (do shell script "
ps -o pid,tty,tpgid,pgid,state,command |
awk '
    BEGIN   {t=ARGV[1];ARGC=1}
    $2==t && $3==$4 {print $1}
' " & quoted form of tty)
    if pids is {} or pids is {""} then
        display dialog "Could not find the processes for " & tty & "." buttons "Cancel" cancel button "Cancel" default button "Cancel"
    end if

    (* Find the unique cwds of those processes. *)
    set text item delimiters to {","}
    set lsof to do shell script "lsof -F 0n -a -d cwd -p " & quoted form of (pids as Unicode text) without altering line endings
    set text item delimiters to {(ASCII character 0) & (ASCII character 10)}
    set cwds to {}
    repeat with lsofItem in text items of lsof
        if lsofItem starts with "n" then
            set cwd to text 2 through end of lsofItem
            if cwds does not contain cwd then ¬
                set end of cwds to cwd
        end if
    end repeat
    if cwds is {} then
        display dialog "No cwds found!?" buttons "Cancel" cancel button "Cancel" default button "Cancel"
    end if
    if length of cwds is greater than 1 then
        set cwds to choose from list cwds with title "Multiple Distinct CWDs" with prompt "Choose the directory to use:" without multiple selections allowed and empty selection allowed
        if cwds is false then error number -128 -- cancel
    end if

    (* Open a new Terminal. *)
    tell application "Terminal" to do script "cd " & quoted form of item 1 of cwds
end run

to extractTTY(a, b)
    set str to textLeftAfterRemovingMatchingHeadAndTail(a, b)
    set offs to offset of "tty" in str
    if offs > 0 then
        return text offs through (offs + 4) of str
    end if
    return ""
end extractTTY
to textLeftAfterRemovingMatchingHeadAndTail(big, little)
    set text item delimiters to space
    if class of big is not list then set big to text items of big
    if class of little is not list then set little to text items of little
    set {maxLen, minLen} to {length of big, length of little}
    if maxLen < minLen then ¬
        set {big, little, maxLen, minLen} to {little, big, minLen, maxLen}

    set start to missing value
    repeat with i from 1 to minLen
        if item i of big is not equal to item i of little then
            set start to i
            exit repeat
        end if
    end repeat
    if start is missing value then
        if maxLen is equal to minLen then
            return ""
        else
            return items (minLen + 1) through end of big as Unicode text
        end if
    end if

    set finish to missing value
    repeat with i from -1 to -minLen by -1
        if item i of big is not equal to item i of little then
            set finish to i
            exit repeat
        end if
    end repeat
    if finish is missing value then set finish to -(minLen + 1)

    return items start through finish of big as Unicode text
end textLeftAfterRemovingMatchingHeadAndTail

Speichern Sie es mit dem Skript-Editor ( AppleScript-Editor in Snow Leopard) und verwenden Sie einen Starter (z. B. FastScripts ), um es einer Taste zuzuweisen (oder führen Sie es einfach über das AppleScript-Menü aus (aktiviert über / Applications / AppleScript / AppleScript Utility.app )).

Chris Johnsen
quelle
1

Ich habe ein Skript veröffentlicht , das den obigen Code von Chris Johnsen verwendet , und ein anderes Skript, um die neue Registerkarte im aktuellen Verzeichnis mit den aktuellen Einstellungen zu öffnen, hauptsächlich, weil ich meine Terminals farblich koordiniere. Vielen Dank, Chris, für dieses Skript, ich benutze es jetzt seit ein paar Monaten und es ist eine großartige Zeitersparnis.

(* Dieses Skript öffnet eine neue Registerkarte Terminal.app im Verzeichnis der aktuellen Registerkarte mit denselben Einstellungen. Sie müssen den Zugriff für unterstützende Geräte aktivieren, sofern dies noch nicht geschehen ist, wie hier beschrieben: http: // www .macosxautomation.com / applescript / uiscripting / index.html

Es ist fast die ganze Arbeit von zwei Skripten zusammen, danke an sie:

Chris Johnsens Skript öffnet eine neue Registerkarte im aktuellen Verzeichnis: OS X Terminal.app: Wie wird eine neue Registerkarte im selben Verzeichnis wie die aktuelle Registerkarte erstellt?

Mit dem "menu_click" von Jacob Rus kann ich den Tab mit denselben Einstellungen erstellen wie mit der API von Terminal: http://hints.macworld.com/article.php?story=20060921045743404

Wenn Sie den Namen eines Terminal-Profils ändern, gibt die AppleScript-API den alten Namen zurück, bis Sie die Anwendung neu starten, sodass das Skript bis dahin nicht mit umbenannten Einstellungen funktioniert. Pfui. Die Notwendigkeit, Terminal für die Ausführung des Menübefehls zu aktivieren, bringt alle Terminalfenster nach vorne.

*)

-- from http://hints.macworld.com/article.php?story=20060921045743404
-- `menu_click`, by Jacob Rus, September 2006
-- 
-- Accepts a list of form: `{"Finder", "View", "Arrange By", "Date"}`
-- Execute the specified menu item.  In this case, assuming the Finder 
-- is the active application, arranging the frontmost folder by date.

on menu_click(mList)
    local appName, topMenu, r

    -- Validate our input
    if mList's length < 3 then error "Menu list is not long enough"

    -- Set these variables for clarity and brevity later on
    set {appName, topMenu} to (items 1 through 2 of mList)
    set r to (items 3 through (mList's length) of mList)

    -- This overly-long line calls the menu_recurse function with
    -- two arguments: r, and a reference to the top-level menu
    tell application "System Events" to my menu_click_recurse(r, ((process appName)'s ¬
        (menu bar 1)'s (menu bar item topMenu)'s (menu topMenu)))
end menu_click

on menu_click_recurse(mList, parentObject)
    local f, r

    -- `f` = first item, `r` = rest of items
    set f to item 1 of mList
    if mList's length > 1 then set r to (items 2 through (mList's length) of mList)

    -- either actually click the menu item, or recurse again
    tell application "System Events"
        if mList's length is 1 then
            click parentObject's menu item f
        else
            my menu_click_recurse(r, (parentObject's (menu item f)'s (menu f)))
        end if
    end tell
end menu_click_recurse



-- with the noted slight modification, from /superuser/61149/os-x-terminal-app-how-to-start-a-new-tab-in-the-same-directory-as-the-current-ta/61264#61264

on run
    (* Find the tty. *)
    -- This is ugly. But is seems to work on Tiger. Maybe newer releases can do better.
    tell application "Terminal"
        set w to the front window
        tell w
            set origName to name
            set title displays device name to not title displays device name
            set newName to name
            set title displays device name to not title displays device name
        end tell
    end tell
    set tty to extractTTY(origName, newName)
    if tty is "" then
        display dialog "Could not find the tty for of the current Terminal window." buttons "Cancel" cancel button "Cancel" default button "Cancel"
    end if

    (* Find the PIDs of the processes in the foreground process group on that tty. *)
    set pids to paragraphs of (do shell script "
ps -o pid,tty,tpgid,pgid,state,command |
awk '
    BEGIN   {t=ARGV[1];ARGC=1}
    $2==t && $3==$4 {print $1}
' " & quoted form of tty)
    if pids is {} or pids is {""} then
        display dialog "Could not find the processes for " & tty & "." buttons "Cancel" cancel button "Cancel" default button "Cancel"
    end if

    (* Find the unique cwds of those processes. *)
    set text item delimiters to {","}
    set lsof to do shell script "lsof -F 0n -a -d cwd -p " & quoted form of (pids as Unicode text) without altering line endings
    set text item delimiters to {(ASCII character 0) & (ASCII character 10)}
    set cwds to {}
    repeat with lsofItem in text items of lsof
        if lsofItem starts with "n" then
            set cwd to text 2 through end of lsofItem
            if cwds does not contain cwd then ¬
                set end of cwds to cwd
        end if
    end repeat
    if cwds is {} then
        display dialog "No cwds found!?" buttons "Cancel" cancel button "Cancel" default button "Cancel"
    end if
    if length of cwds is greater than 1 then
        set cwds to choose from list cwds with title "Multiple Distinct CWDs" with prompt "Choose the directory to use:" without multiple selections allowed and empty selection allowed
        if cwds is false then error number -128 -- cancel
    end if

    (* Open a new Terminal. *)

    -- Here is where I substituted the menu_click call to use the current settings

    tell application "Terminal"
        activate
        tell window 1
            set settings to name of current settings in selected tab
        end tell
    end tell
    menu_click({"Terminal", "Shell", "New Tab", settings})

    tell application "Terminal" to do script "cd " & quoted form of item 1 of cwds in selected tab of window 1
end run

to extractTTY(a, b)
    set str to textLeftAfterRemovingMatchingHeadAndTail(a, b)
    set offs to offset of "tty" in str
    if offs > 0 then
        return text offs through (offs + 6) of str
    end if
    return ""
end extractTTY
to textLeftAfterRemovingMatchingHeadAndTail(big, little)
    set text item delimiters to space
    if class of big is not list then set big to text items of big
    if class of little is not list then set little to text items of little
    set {maxLen, minLen} to {length of big, length of little}
    if maxLen < minLen then ¬
        set {big, little, maxLen, minLen} to {little, big, minLen, maxLen}

    set start to missing value
    repeat with i from 1 to minLen
        if item i of big is not equal to item i of little then
            set start to i
            exit repeat
        end if
    end repeat
    if start is missing value then
        if maxLen is equal to minLen then
            return ""
        else
            return items (minLen + 1) through end of big as Unicode text
        end if
    end if

    set finish to missing value
    repeat with i from -1 to -minLen by -1
        if item i of big is not equal to item i of little then
            set finish to i
            exit repeat
        end if
    end repeat
    if finish is missing value then set finish to -(minLen + 1)

    return items start through finish of big as Unicode text
end textLeftAfterRemovingMatchingHeadAndTail
Rücktaste
quelle
1

Wie an anderer Stelle erwähnt , sollten Sie, wenn Sie Oh My Zsh verwenden , einfach das terminalappPlugin hinzufügen . In Ihrer .zshrc-Datei (vorausgesetzt, Sie verwenden bereits das Git-Plugin):

plugins=(terminalapp git)
Joshua J. McKinnon
quelle
0

Ich benutze dieses Alias ​​/ Shell-Skript, um es zu tun.

# modified from http://www.nanoant.com/programming/opening-specified-path-in-terminals-new-tab
alias twd=new_terminal_working_directory
function new_terminal_working_directory() {
osascript <<END 
        tell application "Terminal"
            tell application "System Events" to tell process "Terminal" to keystroke "t" using command down
        do script "cd $(pwd)" in first window
    end tell
END
}
Ted Naleid
quelle
1
Das sieht so aus, als hätte es Probleme, wenn der CWD bestimmte Zeichen enthält (Shell-Metazeichen und Kontroll-Token; z. B. ein Verzeichnis mit einem Leerzeichen).
Chris Johnsen