Как я могу сделать сценарий, который открывает окна терминала и выполняет команды в них?

У меня есть три скрипта, которые я должен запустить, когда я запускаю свою машину Ubuntu, они запускают сервисы, которые я использую в своей среде разработки.

Чтобы сделать это, я вручную открываю три терминала и тип в командах.

Там какой-либо путь состоит в том, чтобы создать сценарий, который откроет три терминала и выполнит одну команду в каждом из них? (Каждая команда должна быть в отдельном окне терминала, таким образом, я вижу их вывод).

188
задан 24 January 2013 в 03:01

7 ответов

gnome-terminal -- command

или

xterm -e command

или

konsole -e command

Почти

terminal -e command

Чтобы терминал оставался при выходе команды:

В konsole есть флаг --noclose.

В xterm флаг - hold.

В gnome-терминале перейдите к Edit -> Profile Preferences -> Title. Перейдите на вкладку Command. Выберите Удерживайте клемму в раскрывающемся меню с надписью Когда команда выходит . Для этого нужно создать новый профиль и выполнить с помощью

gnome-terminal --window-with-profile=NAMEOFTHEPROFILE -e command
169
ответ дан 22 November 2019 в 22:53

Вместо жесткого кодирования gnome-терминала, konsole, и т.д., используйте систему Alternatives. Программа, которая выполняет эмулятор терминала по умолчанию:

x-terminal-emulator

В моей системе она открывает новый экземпляр Konsole каждый раз, когда я выполняю эту команду.

К счастью, кажется, что терминалы поддерживают опцию -e для выполнения команды (я проверил ее для konsole и gnome-terminal). Аргументы после команды передаются вызываемой команде. Бэш отказывается оставаться открытым в моем терминале, для получения терминала нужен дополнительный скрипт:

#!/bin/sh
"$@"
exec "$SHELL"

Если вы сохранили предыдущий скрипт как /home/user/hacky и сделали его исполняемым, вы запустите свои скрипты с:

x-terminal-emulator -e /home/user/hacky your-script optional arguments here

Требуется полный путь и /home/user/hacky должен быть исполняемым.

Моя предыдущая попытка запустить скрипт в новом терминальном окне может быть найдена в ревизии #2, это было до того, как я понял, что аргументы могут быть переданы в x-terminal-emulator.

70
ответ дан 22 November 2019 в 22:53

Проще говоря-

#!/bin/bash

/etc/init.d/ccpd status

Этого достаточно для другие команды, которым не нужно ничего отображать в терминале. Но здесь нужно видеть отображаемый статус.
Итак, он должен запускаться в окне терминала

#!/bin/bash

gnome-terminal -e "/etc/init.d/ccpd status"  --window-with-profile=NAMEOFTHEPROFILE

Другой пост предназначался [] как заполнитель

Здесь «NAMEOFTHEPROFILE» следует заменить на имя профиля, который «Содержит терминал, когда команда завершается ".

enter image description here

enter image description here

10
ответ дан 22 November 2019 в 22:53

Используйте экранную команду и -d отсоединиться от существующего сеанса экрана и снова подключить здесь -m инициировать новый сеанс экрана -S создайте именованный сеанс вместо использования имени по умолчанию

-3
ответ дан 22 November 2019 в 22:53

, комментируя ответ от Lekensteyn. Я знаю, что это старая заметка, но для всех, кто находит это полезным (как я только что сделал). Вместо того, чтобы делать очередной "хаки-скрипт", просто поместите функцию в вызываемый вами скрипт

hacky_function()
{
"$@"
exec "$SHELL"
}

Вызовите скрипт с "x-terminal-emulator -e /path/to/script hacky_function optional arguments here"

Не забудьте поставить "$@" в конце скрипта

1
ответ дан 22 November 2019 в 22:53

ОБНОВЛЕНИЕ 17 ФЕВРАЛЯ 2020 ГОДА: этот ответ теперь устарел.

Щелкните эту ссылку и используйте вместо этого другой ответ: Откройте Терминал с несколькими вкладками и выполните приложение .


С помощью ответа @ nickguletskii и моего собственного комментария под его ответом, а также вдохновленного голосом @ grabantot моего комментария, вот мой предпочтительный способ сделать это, особенно когда я хочу, чтобы терминал оставался открытым, чтобы Затем я могу использовать его вручную.

Исх. использование: это действительно полезно для добавления в ваши программы запуска, чтобы этот сценарий запускался, открывал терминал, создавал и называл вкладку в терминале и запускал команду за вас. Или вы можете просто добавить символическую ссылку на этот скрипт на свой рабочий стол. Я использую этот тип подхода, поэтому я могу дважды щелкнуть один значок на моем рабочем столе и открыть несколько терминалов (с различными вкладками, названными в зависимости от того, какую работу я собираюсь выполнять в них) и программ для настройки моя среда программирования, например, для повседневной работы.

Вот надуманный пример, который открывает одну вкладку, называет ее «тест», а затем запускает простую команду cd / etc; ls внутри него. Часть $ SHELL в конце заставляет оболочку оставаться открытой, чтобы вы могли увидеть ее вывод и продолжить его использование (я узнал об этом где-то еще в Stack Overflow):

gnome-terminal --tab --title="test" --command="bash -c 'cd /etc; ls; $SHELL'"

Вот более сложный пример, открывает 3 отдельные вкладки в одном и том же gnome-терминале. Это именно то, что делает мой ярлык на рабочем столе, поэтому я могу открыть сразу несколько окон программирования:

gnome-terminal --tab --title="tab 1" --command="bash -c 'cd /etc; ls; $SHELL'" --tab --title="tab 2" --command="bash -c 'cd ~; ls; $SHELL'" --tab --title="tab 3" --command="bash -c 'cd ~/temp3; ls; $SHELL'"

Вот разбивка этой команды выше:

  • gnome-terminal = открыть gnome- терминал
  • - tab = открыть уникальную вкладку, чтобы узнать, что будет дальше
  • - title = "tab 1" = название этой вкладки "tab 1"
  • - command = " bash -c 'cd / etc; ls; $ SHELL' " = запустить bash -c 'cd / etc; ls; $ SHELL ', которую я только что придумал в качестве примера; вот что он делает:
    • bash -c говорит, что это команда bash 'c'ommand
    • cd / etc =' c'hange 'd'irectory в путь "/ etc"
    • ls = 'l'i's't содержимое этого каталога
    • $ SHELL = этот загадочный лакомый кусочек необходим для того, чтобы оболочка оставалась открытой, чтобы вы могли с ней работать. Если вы хотите, чтобы оболочка открылась, запустите вашу команду, затем закройте, просто удалите эту часть. Однако я хочу, чтобы вкладка оставалась открытой, чтобы я мог творить волшебство программирования. :)
  • затем мы начинаем снова с части - tab , чтобы создать вкладку 2, затем снова для вкладки 3. Настройте так, как вам нравится.

Снимок экрана:

enter image description here

8
ответ дан 22 November 2019 в 22:53

Почти десять лет спустя вечеринку, но вот мой ответ с использованием Python.

В приведенном ниже .gif я запустил программу с существующего терминала с запущенным устройством записи экрана, чтобы показать, как это будет выглядеть при входе в систему:

dellstart.gif

Я написал программу на Python для этого ответа. Есть некоторые дополнительные функции, не запрашиваемые OP, но полезные для меня:

  • Запускается при автозапуске для настройки приложений с графическим интерфейсом, часто используемых после входа в систему.
  • Открывает несколько вкладок gnome-terminal .
  • Назначить заголовок на вкладки терминала.
  • Перемещает окна в предпочтительное положение на рабочем столе.
  • Открывает gedit и последние пять открытых файлов на отдельных вкладках.

Программа python:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#==============================================================================
#
#       dellstart - Autostart GUI applications on Dell Fileserver
#
#==============================================================================

'''
CALL:

   dellstart

REQUIRES:

   sudo apt install xdotool
    
'''

from __future__ import print_function           # Must be first import
import os
import time

BASHRC_TIME = 2                                 # Seconds to load ~/.bashrc
WINDOW_TIME = .5                                # Secpmds fpr window to appear

commands = [ 'gnome-terminal &',                # Launch terminal in background
             'sleep '+str(BASHRC_TIME),         # Bash command wait a sec
             'move x y',                        # Move windows to x and/or y
#             'move 2100 1000',                  # triple monitor setup
             'xdotool type "cd ~"',             # Change to home directory
             'xdotool key Return',              # Enter Key
             'xdotool type "./ssh-activity"',   # Suspend after 15 minutes
             'xdotool key Return',              # Enter Key
             'title SSH\ Activity',             # Window title (escape spaces)
             'xdotool key Control_L+Shift_L+T', # Open new terminal tab
             'sleep '+str(BASHRC_TIME),         # Bash command wait a sec
             'xdotool type "cd ~/askubuntu"',   # Change to working directory
             'xdotool key Return',              # Enter Key
             'title Ask\ Ubuntu',               # Window title (escape spaces)
             'gedit',                           # Last 5 files will open up
             'move x y',                        # Move windows to x and/or y
#             'move 3849 2266',                  # triple monitor setup
           ]

""" NOTE: To discover window coordinates, arrange on desktop and type:

        wmctrl -lG
"""

def process_commands(command_list):

    for command in command_list:

        if command.endswith('&'):
            # Launch in background and get window ID opened
            active_pid, active_win = launch_command(command)
            if active_pid == 0:
                print("ERROR launching", command, \
                "Aborting 'dellstart' script")
                exit()

        elif command.startswith('move'):
            move_window(command, active_win)

        elif command.startswith('title'):
            terminal_title(command)

        elif command.startswith('gedit'):
            gedit()

        else:
            run_and_wait(command)


def launch_command(ext_name):
    ''' Launch external command in background and return PID to parent.
        Use for programs requiring more than .2 seconds to run.
    '''

    all_pids = get_pids(ext_name)       # Snapshot current PID list
    all_wins = get_wins(all_pids)       # Snapshot of windows open
    new_pids = all_pids
    new_wins = all_wins
    sleep_count = 0                     # Counter to prevent infinite loops

    os.popen(ext_name)                  # Run command in background

    while new_pids == all_pids:         # Loop until new PID is assigned
        new_pids = get_pids(ext_name)   # Snapshot current PID list
        if sleep_count > 0:             # Don't sleep first time through loop
            time.sleep(.005)            # sleep 5 milliseconds
        sleep_count += 1
        if sleep_count == 1000:         # 10 second time-out
            print('launch_ext_command() ERROR: max sleep count reached')
            print('External command name:',ext_name)
            return 0

    pid_list = list(set(new_pids) - set(all_pids))
    if not len(pid_list) == 1:
        print('launch_command() ERROR: A new PID could not be found')
        return 0, 0

    time.sleep(WINDOW_TIME)             # Give time for window to appear
    new_wins = get_wins(all_pids)       # Snapshot of windows open
    win_list = list(set(new_wins) - set(all_wins))
    if not len(win_list) == 1:
        #print('launch_command() ERROR: New Window ID could not be found')
        #suppress error message because we aren't using window ID at all
        return int(pid_list[0]), 0

    # Return PID of program we just launched in background
    return int(pid_list[0]), int(win_list[0])


def run_and_wait(ext_name):
    ''' Launch external command and wait for it to end.
        Use for programs requiring less than .2 seconds to run.
    '''

    result = os.popen(ext_name).read().strip()
    #print('run_and_wait() command:', ext_name)
    return result


def get_pids(ext_name):
    ''' Return list of PIDs for program name and arguments
        Whitespace output is compressed to single space
    '''
    all_lines = []
    # Just grep up to first space in command line. It was failing on !
    prog_name = ext_name.split(' ',1)[0]
    all_lines = os.popen("ps aux | grep -v grep | grep " + \
                        "'" + prog_name + "'").read().strip().splitlines
    PID = []
    for l in all_lines():
        l = ' '.join(l.split())         # Compress whitespace into single space
        PID.append(int(l.split(' ', 2)[1]))

    return PID


def get_wins(all_pids):
    ''' Return list of all windows open under PID list
        Currently unncessary because we work on active window '''
    windows = []
    for pid in all_pids:
        all_lines = os.popen('xdotool search --pid ' + str(pid)). \
                             read().strip().splitlines
        for l in all_lines():
            windows.append(int(l))

    return windows


def move_window(line, active_win):
    ''' Move window to x y coorindates on Desktop

        If the letter x or y is passed, that dimension remains unchanged eg:

            xdotool getactivewindow windowmove 100 100    # Moves to 100,100
            xdotool getactivewindow windowmove x 100      # Moves to x,100
            xdotool getactivewindow windowmove 100 y      # Moves to 100,y

    '''
    line = ' '.join(line.split())       # Compress whitespace to single space
    x = line.split(' ')[-2]
    y = line.split(' ')[-1]

    # We don't need to pass window ID as last active window defaults
    all_lines = os.popen('xdotool getactivewindow windowmove ' + x + ' ' + y). \
                         read().strip().splitlines
    for l in all_lines():
        print(l)


def terminal_title(new_title):
    ''' Rather awkward calling xdotool which chokes on double quotes and bash
        via python which chokes on backslashes.

        Simple format (if it worked) would be:
            command = r'PS1="${PS1/\\u@\\h: \\w/' + title + '}"'

        The bash function copied from is:
            function termtitle() { PS1="${PS1/\\u@\\h: \\w/$@}"; }

        Reference for xdotool keycodes: 
        https://gitlab.com/cunidev/gestures/-/wikis/xdotool-list-of-key-codes
    '''

    title = new_title.split(' ', 1)[1]   # Strip out leading "title" token

    command = 'xdotool type PS1='
    run_and_wait(command)
    run_and_wait('xdotool key quotedbl')
    command = 'xdotool type $'
    run_and_wait(command)
    run_and_wait('xdotool key braceleft')
    command = 'xdotool type PS1/'
    run_and_wait(command)
    run_and_wait('xdotool key backslash')
    run_and_wait('xdotool key backslash')
    command = 'xdotool type u@'
    run_and_wait(command)
    run_and_wait('xdotool key backslash')
    run_and_wait('xdotool key backslash')
    command = 'xdotool type "h: "'
    run_and_wait(command)
    run_and_wait('xdotool key backslash')
    run_and_wait('xdotool key backslash')
    command = 'xdotool type "w/"'
    run_and_wait(command)
    command = 'xdotool type "' + title + '"'
    run_and_wait(command)
    run_and_wait('xdotool key braceright')
    run_and_wait('xdotool key quotedbl')
    run_and_wait('xdotool key Return')


def gedit():

    last_modified_files = gedit_recent_files()
    command = 'gedit '
    for f in last_modified_files:
        command=command+'"'
        command=command+f
        command=command+'" '
    # Open gedit with last five modfied files
    command=command+' &'
    active_pid, active_win = launch_command(command)
    if active_pid == 0:
        print("ERROR launching", command, \
        "Aborting 'dellstart' script")
        exit()


def gedit_recent_files():
    ''' Get list of gedit 5 most recent files:
    
grep --no-group-separator -B5 'group>gedit' ~/.local/share/recently-used.xbel | sed -n 1~6p | sed 's#  <bookmark href="file:///#/#g' | sed 's/"//g'

/home/rick/python/mmm added=2020-05-02T15:34:55Z modified=2020-11-19T00:43:45Z visited=2020-05-02T15:34:56Z>
/home/rick/python/mserve added=2020-07-26T16:36:09Z modified=2020-11-28T01:57:19Z visited=2020-07-26T16:36:09Z>

    '''
    command = "grep --no-group-separator -B5 'group>gedit' " + \
              "~/.local/share/recently-used.xbel | " + \
              "sed -n 1~6p | sed 's#  <bookmark href=" + '"' + \
              "file:///#/#g' | " + "sed 's/" + '"' + "//g'"

    recent_files = []
    times = []
    all_lines = os.popen(command).read().strip().splitlines
    uniquifier = 1                  # gedit can give all open files same time
    for l in all_lines():
        fname = l.split(' added=', 1)[0]
        trailing = l.split(' added=', 1)[1]
        modified = trailing.split(' modified=', 1)[1]
        modified = modified.split('Z', 1)[0]
        # TODO: 2038
        d = time.strptime(modified, '%Y-%m-%dT%H:%M:%S')
        epoch = time.mktime(d)
        epoch = int(epoch)
        recent_files.append(fname)

        try:
            times.index(epoch)
            # gedit has given multiple files the same modification time
            epoch += uniquifier
            uniquifier += 1
        except:
            pass                    # Not a duplicate time
        times.append(epoch)

    N=5
    top_files = []
    if N > len(times):
        # Less than 5 most recent files in list
        N = len(times)
        if N == 0:
            # No most recent files in list
            return top_files            # return empty list

    # Store list in tmp to retrieve index
    tmp=list(times)
    # Sort list so that largest elements are on the far right
    times.sort()

    #print ('5 most recent from lists and indices')
    for i in range(1, N+1):
        top_files.append(recent_files[tmp.index(times[-i])])

    return top_files


if __name__ == "__main__":

    process_commands(commands)

# end of dellstart

Обратите внимание, что вам может потребоваться поработайте с переменной BASHRC_TIME в вашей системе, чтобы программа работала быстрее. У меня в ~ / .bashrc запущено множество функций, и ваш может работать намного быстрее.

Я планировал написать это много лет, но до сих пор не удосужился до него.

0
ответ дан 5 January 2021 в 23:53

Другие вопросы по тегам:

Похожие вопросы: