Uruchomienie polecenia w nowym oknie terminala Mac OS X.

92

Próbowałem dowiedzieć się, jak uruchomić polecenie bash w nowym oknie Max OS X Terminal.app. Jako przykład, oto jak uruchomiłbym moje polecenie w nowym procesie bash:

bash -c "my command here"

Ale to ponownie wykorzystuje istniejące okno terminala zamiast tworzyć nowe. Chcę coś takiego:

Terminal.app -c "my command here"

Ale to oczywiście nie działa. Znam polecenie „open -a Terminal.app”, ale nie wiem, jak przekazać argumenty do terminala, ani nawet czy wykonałem, jakich argumentów użyć.

Walt D.
źródło
Zawsze można było otworzyć preferencje, przejść do zakładki „Profile”, przejść do strony „Shell” i ustawić tam polecenie uruchamiania. Działa tylko wtedy, gdy aplikacja jest otwarta, ale działa lepiej niż hakerskie alternatywy!
Zane Helton,
Zobacz także to samo pytanie na superuser superuser.com/q/174576/122841
Beetle

Odpowiedzi:

96

Jednym ze sposobów, w jaki mogę to zrobić, jest utworzenie pliku .command i uruchomienie go w następujący sposób:

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

lub użyj applecript:

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

chociaż albo będziesz musiał uciec od wielu podwójnych cudzysłowów, albo nie będziesz w stanie używać apostrofów

cobbal
źródło
Zdecydowałem się na pierwszą metodę. To dość hakerskie, ale działa i nie muszę się martwić o unikanie cudzysłowów w moim poleceniu ani o nic. Dzięki.
Walt D
3
Jeśli polecenie wymaga sparametryzowanego działania, być może będziesz chciał zamienić pojedyncze i podwójne cudzysłowy; chociaż musisz zrozumieć różnicę, aby móc to zrobić poprawnie. osascript -e "tell application \"Terminal\" to do script \"echo '$variable'\"'
tripleee
ktoś wie, jak zamknąć głupie pozostawione okno terminala?
Nicholas DiPiazza,
Dodaj ; exitna końcu poleceń skryptu powłoki, na przykład do script "echo hello; exit". Nadal musisz zamknąć okno osobno.
tripleee
65

Częściowe rozwiązanie:

Umieść rzeczy, które chcesz zrobić, w skrypcie powłoki, tak jak to

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

I nie zapomnij o ' chmod +x file', aby uczynić go wykonywalnym. Wtedy możesz

open -a Terminal.app scriptfile

i będzie działać w nowym oknie. Dodaj „ bash” na końcu skryptu, aby nie dopuścić do zakończenia nowej sesji. (Chociaż być może będziesz musiał dowiedzieć się, jak załadować pliki rc użytkowników i takie tam ...)

0scar
źródło
7
Kontekst nowo otwartego okna wydaje się być folderem głównym użytkownika /Users/{username}. Czy istnieje sposób, aby folder kontekstowy był taki sam jak okno terminala nadrzędnego, które go otworzyło?
Johnny Oshika
> Chociaż być może będziesz musiał wymyślić, jak załadować pliki rc użytkowników i takie tam ... użyj do tego bash -l
Aivar
35

Próbowałem to zrobić od jakiegoś czasu. Oto skrypt, który zmienia się w ten sam katalog roboczy, uruchamia polecenie i zamyka okno terminala.

#!/bin/sh 
osascript <<END 
tell application "Terminal"
    do script "cd \"`pwd`\";$1;exit"
end tell
END
bez powiek
źródło
Nie podoba ci się zaakceptowany skrypt, twój jeden rozwiązuje bieżący problem z katalogiem. Dzięki!
Marboni
Świetne rozwiązanie; jednak wypisuje coś w rodzaju tab 1 of window id 7433stdout w powłoce startowej . Aby to stłumić, umieść >/dev/null wcześniej <<END .
mklement0
1
To nie powoduje zamknięcia okna terminala. Po prostu zamyka interpreter poleceń. Terminal.app musi być skonfigurowany tak, aby zamykał okno automatycznie lub przy czystym wyjściu interpretera poleceń.
user66001
8

Jeśli kogoś to obchodzi, oto odpowiednik dla 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
Al Chou
źródło
3

Oto jeszcze jedno podejście (również przy użyciu 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' 

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


źródło
3

Zrobiłem wersję funkcji odpowiedzi Oscara, ta również kopiuje środowisko i zmiany do odpowiedniego katalogu

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

Możesz go używać w ten sposób:

new_window my command here

lub

new_window ssh example.com
Dave Butler
źródło
1
Linia TMP_FILE="tmp.command"może stanowić problem, jeśli uruchomisz więcej niż jeden proces jednocześnie. Sugerowałbym zastąpienie goTMP_FILE=$(mktemp "/tmp/command.XXXXXX")
duthen
2

Oto mój niesamowity skrypt, w razie potrzeby tworzy nowe okno terminala i przełącza się do katalogu, w którym znajduje się Finder, jeśli Finder jest na pierwszym miejscu. Ma wszystkie maszyny potrzebne do wykonywania poleceń.

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
w00t
źródło
1

Kolega zapytał mnie, jak otworzyć DUŻO sesji ssh na raz. Użyłem odpowiedzi Cobbala, aby napisać ten skrypt:

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

Aktualizując listę poleceń (nie muszą to być wywołania ssh), otrzymasz dodatkowe otwarte okno dla każdego wykonywanego polecenia. Na sleep 60końcu służy do przechowywania .commandplików podczas ich wykonywania. W przeciwnym razie powłoka kończy się zbyt szybko, wykonując pułapkę w celu usunięcia katalogu tymczasowego (utworzonego przez mktemp), zanim uruchomione sesje będą miały możliwość odczytania plików.

znak
źródło
0

Możesz także wywołać nową funkcję polecenia Terminala, naciskając Shift + ⌘ + Nkombinację klawiszy. Polecenie, które umieścisz w pudełku, zostanie uruchomione w nowym oknie terminala.

ayaz
źródło
Oczywiście warto wiedzieć, ale muszę to zrobić programowo. Gdy mój program wygeneruje plik .command, a następnie go otworzy, jest to rozsądne (choć trochę hakerskie) rozwiązanie.
Walt D
0

Nazywam ten skrypt skryptu. Proponuję umieścić go w katalogu w twojej ścieżce do pliku wykonywalnego. Upewnij się, że jest wykonywalny w następujący sposób:

chmod +x ~/bin/trun

Następnie możesz uruchamiać polecenia w nowym oknie, po prostu dodając przed nimi trun, na przykład:

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

Oto scenariusz. Robi kilka wymyślnych rzeczy, takich jak przekazywanie argumentów, zmiana paska tytułu, czyszczenie ekranu w celu usunięcia bałaganu przy uruchamianiu powłoki, usuwanie pliku po zakończeniu. Używając unikalnego pliku dla każdego nowego okna, można go używać do tworzenia wielu okien jednocześnie.

#!/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
zrozumiałem
źródło
1
Nieprawidłowe użycie $*całości zrujnuje nietrywialne cytowanie w danych wejściowych. Chcesz "$@"zamiast tego.
tripleee
Szukałem open -b com.apple.terminal. Dzięki
Ebru Yener