Programmatically launch Terminal.app with a specified command (and custom colors)

后端 未结 6 709
夕颜
夕颜 2020-12-08 01:03

I can launch an xterm from the command line (or a program, via a system call) like so:

/usr/X11/bin/xterm -fg SkyBlue -bg black -e myscript

相关标签:
6条回答
  • 2020-12-08 01:18

    You can open an app by bundle id too, and give other parameters.

    If there's an executable script test.sh in the current directory, the following command will open and run it in Terminal.app

     open -b com.apple.terminal test.sh 
    

    The only down side that I can find is that Terminal doesn't appear to inherit your current environment, so you'll have to arrange another way to pass parameters through to the script that you want to run. I guess building the script on the fly to embed the parameters would be one approach (taking into account the security implications of course...)

    0 讨论(0)
  • 2020-12-08 01:22

    The answer from @david-moles above works but run the terminal and command in ~ rather the current working directory where term was launched. This variation adds a cd command.

    #!/usr/bin/env bash
    # based on answer by @david-moles in 
    # https://stackoverflow.com/questions/4404242/programmatically-launch-terminal-app-with-a-specified-command-and-custom-colors
    echo "
    on run argv
      if length of argv is equal to 0
        set command to \"\"
      else
        set command to item 1 of argv
      end if
      set command to \"cd '"$PWD"' ;\" & command
      if length of argv is greater than 1
        set profile to item 2 of argv
        runWithProfile(command, profile)
      else
        runSimple(command)
      end if
    end run
    
    on runSimple(command)
      tell application \"Terminal\"
        activate
        set newTab to do script(command)
      end tell
      return newTab
    end runSimple
    
    on runWithProfile(command, profile)
      set newTab to runSimple(command)
      tell application \"Terminal\" to set current settings of newTab to (first settings set whose name is profile)
    end runWithProfile
    " | osascript - "$@" > /dev/null
    

    There may be a way to set PWD this with applescript.

    Note: When I use this, I sometimes two Terminal windows, one a shell running in ~ and a second which runs the cd command and command from argv[1]. Seems to happen if Terminal is not already running; perhaps it is opening old state (even tho I had no open terminals when I closed it).

    0 讨论(0)
  • 2020-12-08 01:28

    you can launch terminal with the following command, not sure how to specify colors:

     open /Applications/Utilities/Terminal.app/
    
    0 讨论(0)
  • 2020-12-08 01:29

    Assuming you already have the colors you want in one of your Terminal profiles, here's what I came up with (with some help from Juha's answer and from this Serverfault answer).


    Update:

    On reflection, I think this echo business is too complicated. It turns out you can use osascript to make an executable AppleScript file with a shebang line:

    #!/usr/bin/osascript                                                                            
    
    on run argv                                                                                     
      if length of argv is equal to 0                                                               
        set command to ""                                                                           
      else                                                                                          
        set command to item 1 of argv                                                               
      end if                                                                                        
    
      if length of argv is greater than 1                                                           
        set profile to item 2 of argv                                                               
        runWithProfile(command, profile)                                                            
      else                                                                                          
        runSimple(command)                                                                          
      end if                                                                                        
    end run                                                                                         
    
    on runSimple(command)                                                                           
      tell application "Terminal"                                                                   
        activate                                                                                    
        set newTab to do script(command)                                                            
      end tell                                                                                      
      return newTab                                                                                 
    end runSimple                                                                                   
    
    on runWithProfile(command, profile)                                                             
      set newTab to runSimple(command)                                                              
      tell application "Terminal" to set current settings of newTab to (first settings set whose name is profile)                                                                                      
    end runWithProfile
    

    Save that as term.scpt, make it executable with chmod +x, and use it the same way as below, e.g. term.scpt "emacs -nw" "Red Sands".


    Original answer:

    Assuming we save the script below as term.sh...

    #!/bin/sh
    
    echo '
    on run argv
      if length of argv is equal to 0
        set command to ""
      else
        set command to item 1 of argv
      end if
    
      if length of argv is greater than 1
        set profile to item 2 of argv
        runWithProfile(command, profile)
      else
        runSimple(command)
      end if
    end run
    
    on runSimple(command)
      tell application "Terminal"
        activate
        set newTab to do script(command)
      end tell
      return newTab
    end runSimple
    
    on runWithProfile(command, profile)
      set newTab to runSimple(command)
      tell application "Terminal" to set current settings of newTab to (first settings set whose name is profile)
    end runWithProfile
    ' | osascript - "$@" > /dev/null
    

    ...it can be invoked as follows:

    • term.sh
      • opens a new terminal window, nothing special
    • term.sh COMMAND
      • opens a new terminal window, executing the specified command. Commands with arguments can be enclosed in quotes, e.g. term.sh "emacs -nw" to open a new terminal and run (non-windowed) emacs
    • term.sh COMMAND PROFILE
      • opens a new terminal window, executing the specified command, and sets it to the specified profile. Profiles with spaces in their names can be enclosed in quotes, e.g. term.sh "emacs -nw" "Red Sands" to open a new terminal and run (non-windowed) emacs with the Red Sands profile.

    If you invoke it with a bad command name, it'll still open the window and set the profile, but you'll get bash's error message in the new window.

    If you invoke it with a bad profile name, the window will still open and the command will still execute but the window will stick with the default profile and you'll get an error message (to stderr wherever you launched it) along the lines of

    525:601: execution error: Terminal got an error: Can’t get settings set 1 whose name = "elvis". Invalid index. (-1719)

    The invocation is slightly hacky, and could probably be improved if I took the time to learn getopt (e.g., something like term.sh -p profile -e command would be better and would, for instance, allow you to easily open a new terminal in the specified profile without invoking a command). And I also wouldn't be surprised if there are ways to screw it up with complex quoting. But it works for most purposes.

    0 讨论(0)
  • 2020-12-08 01:31

    Almost all (every?) osx program can be launched from command line using:

    appName.app/Contents/MacOS/command

    For terminal the command is:

    /Applications/Utilities/Terminal.app/Contents/MacOS/Terminal

    You can use the autocomplete (tab) or ls to find the correct filenames. ".app" is basically a folder.

    To change the colors and run a script... I think you cannot do it with shell scripts as Terminal does not accept arguments ("Terminal myScript.sh" does not launch myScript). With iTerm this works.

    Workaround is to use applescript (wrapped in a shell script):

       #!/bin/sh
       osascript -e '
         tell application "Terminal"
           activate
           tell window 1
              do script "sleep 5; exit"
              set background color to {0, 11111, 11111}
              set win_id to id
           end tell
    
           set w_ids to (id of every window)
    
           repeat while w_ids contains win_id
             delay 1
             set w_ids to (id of every window)
           end repeat
        end tell'
    

    Ok, now it should behave exactly the same as the xterm example. The drawback is the constant polling of the window ids (which is bad programming).

    edit: A bit more elegant applescript would use the 'busy' property of Terminal. I will leave the original code as is works for a general program (not just terminal).

    tell application "Terminal"
        tell window 1
            do script "sleep 2"
            set background color to {0, 11111, 11111}
            repeat while busy
                delay 1
            end repeat
            close
        end tell
    end tell
    

    Also for perfectly correct program, one should check that whether the terminal is running or not. It affects the number of windows opened. So, this should be run first (again a nasty looking hack, that I will edit later as I find a working solution).

    tell application "System Events"
        if (count (processes whose name is "Terminal")) is 0 then
            tell application "Terminal"
                tell window 1
                    close
                end tell
            end tell
        end if
    end tell
    

    br,
    Juha

    0 讨论(0)
  • 2020-12-08 01:39

    You can also go into terminal GUI, completely configure the options to your heart's content, and export them to a ".terminal" file, and/or group the configurations into a Window Group and export that to a terminal file "myGroup.terminal". Then

    open myGroup.terminal

    will open the terminal(s) at once, with all your settings and startup commands as configured.

    0 讨论(0)
提交回复
热议问题