OS X Terminal.app: làm thế nào để bắt đầu một tab mới trong cùng thư mục với tab hiện tại?


24

Tôi thường xuyên cần mở một tab mới trong cùng thư mục với tab hiện tại của mình để làm việc khác trong khi tab hiện tại của tôi bị chiếm bởi một quá trình chạy dài. Tuy nhiên, theo mặc định khi bạn tạo một tab mới, Terminal.app bắt đầu lúc ~ /. Bất kỳ ý tưởng làm thế nào để làm cho nó tự động nhảy?


Cảm ơn các bạn đã phản hồi nhanh chóng! Tôi ổn khi khởi chạy một tab mới bằng cách gọi một tập lệnh, nhưng tôi tự hỏi liệu có cách nào khác để làm điều đó không vì tôi không thể chạy tập lệnh nếu đã có chương trình đang chạy và chiếm giữ tab hiện tại: |
Riobard

Câu trả lời:


10

Trong OS X 10.7 (Lion), Terminal.app hỗ trợ nguyên bản này: New Windows/Tabs open in: Same working directory


Thật tệ khi Apple không làm backport ... rất thích thấy tính năng này trong Snow Leopard.
Đi lang thang Nauta

4
Tôi đã thiết lập nhưng không làm việc cho tôi. Cửa sổ tùy chọn nói điều gì đó về việc kích hoạt các chuỗi thoát trước khi điều này có thể hoạt động.
Ram trên đường ray

2

Người ta phải rất cẩn thận khi đi qua các chuỗi qua các môi trường khác nhau.

Tôi chạy 10,4, vì vậy tập lệnh 'tfork' của tôi luôn mở một cửa sổ mới thay thế. Nên dễ dàng điều chỉnh nó để sử dụng tab:

#!/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

Thí dụ: tfork git log -p ..FETCH_HEAD


Sửa đổi: cwd của một quy trình đang chạy, chiếm lĩnh một tab Terminal

Ý tưởng về thư mục hiện tại của chương trình chiếm giữ tab hiện tại, không rõ ràng như người ta mong đợi.

Mỗi tab Terminal có một thiết bị tty duy nhất được sử dụng bởi các quy trình mà nó chạy (ban đầu, một vỏ; sau đó, bất cứ thứ gì vỏ bắt đầu).

Mỗi Terminal tty (bình thường) có một nhóm quy trình tiền cảnh duy nhất mà người ta có thể coi là một người chiếm lĩnh Tty.

Mỗi nhóm quy trình có thể có nhiều quy trình trong đó.

Mỗi tiến trình có thể có thư mục làm việc hiện tại của riêng nó (cwd) (một số môi trường cung cấp cho mỗi luồng tương đương cwd hoặc cwd của riêng chúng, nhưng chúng ta sẽ bỏ qua điều đó).

Các sự kiện trước đó thiết lập một loại dấu vết từ tty đến cwd: tty -> nhóm quy trình tiền cảnh -> các quy trình của nhóm quy trình tiền cảnh -> cwds.

Phần đầu tiên (từ các quá trình tty đến tiền cảnh) của vấn đề có thể được giải quyết với đầu ra từ ps :

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

(trong đó, ttyp6, là tên của tty quan tâm)

Việc ánh xạ từ tiến trình (PID) sang cwd có thể được thực hiện với lsof :

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

(trong đó, 2515,2516, là một danh sách các quy trình quan tâm được phân tách bằng dấu phẩy

Nhưng dưới Tiger, tôi thấy không có cách nào trực tiếp để có được tên thiết bị tty của một cửa sổ Terminal cụ thể . Có một cách xấu xí khủng khiếp để có được cái tên tty trong Tiger. Có lẽ Leopard hoặc Snow Leopard có thể làm tốt hơn.

Tôi kết hợp tất cả lại với nhau trong một AppleScript như thế này:

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

Lưu nó với Script Editor ( AppleScript Editor trong Snow Leopard) và sử dụng launcher (ví dụ FastScripts ) để gán nó cho một khóa (hoặc chỉ chạy nó từ menu AppleScript (được bật thông qua / Ứng dụng / AppleScript / AppleScript Utility.app )).


1

Tôi đã đăng một tập lệnh sử dụng mã của Chris Johnsen ở trên và một tập lệnh khác để mở tab mới trong thư mục hiện tại với các cài đặt hiện tại, chủ yếu là do tôi phối hợp các thiết bị đầu cuối của mình. Cảm ơn Chris, vì kịch bản đó, tôi đã sử dụng nó trong vài tháng nay và đó là một trình tiết kiệm thời gian tuyệt vời.

(* Tập lệnh này mở tab Terminal.app mới trong thư mục của tab hiện tại có cùng cài đặt. Nếu bạn chưa có, hãy bật quyền truy cập cho các thiết bị trợ giúp như được mô tả tại đây: http: // www .macosxautomation.com / applescript / uiscripting / index.html

Đó gần như là tất cả công việc của hai kịch bản ghép lại với nhau, cảm ơn bạn:

Kịch bản của Chris Johnsen mở một tab mới trong thư mục hiện tại: OS X Terminal.app: làm thế nào để bắt đầu một tab mới trong cùng thư mục với tab hiện tại?

Menu của Jacob Rus_click 'cho phép tôi tạo tab có cùng cài đặt, vì API của Terminal không: http://hints.macworld.com/article.php?story=20060921045743404

Nếu bạn thay đổi tên của cấu hình Terminal, API AppleScript sẽ trả về tên cũ cho đến khi bạn khởi động lại ứng dụng, do đó, tập lệnh sẽ không hoạt động trên các cài đặt được đổi tên cho đến lúc đó. Ừ Ngoài ra, sự cần thiết phải kích hoạt Terminal để thực thi lệnh menu đưa tất cả các cửa sổ đầu cuối lên phía trước.

*)

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

1

Như đã đề cập ở nơi khác , nếu bạn đang sử dụng Oh My Zsh , thì bạn chỉ nên thêm terminalappplugin. Trong tệp .zshrc của bạn (giả sử bạn đã sử dụng plugin git:

plugins=(terminalapp git)

0

Tôi sử dụng tập lệnh bí danh / shell này để làm điều đó.

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

1
Trông có vẻ như nó sẽ có vấn đề nếu cwd có một số ký tự trong đó (ký tự meta shell và mã thông báo điều khiển; ví dụ: một thư mục có khoảng trắng trong đó).
Chris Johnsen

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.