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

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

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

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

gnome-terminal -- команда

или

xterm -e команда

или

konsole -e команда

Довольно много

терминал -этот команда

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

В консоли есть --noclose флаг.

В xterm есть -hold флаг.

В gnome-terminal, перейти к Редактировать -> Настройки профиля -> Заглавие. Нажмите на Команда вкладка. Выбрать Держите терминал из выпадающего меню с надписью Когда команда завершается. Вы должны создать для этого новый профиль и выполнить с помощью

gnome-терминал --окно-с-профилем=НАЗВАНИЕ ПРОФИЛЯ -этот команда

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

x-terminal-emulator

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

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

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

ОБНОВЛЕНИЕ 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" = заголовок этой вкладки "вкладка 1";
  • --command="bash -c 'cd /etc; ls; $SHELL'" = запустите bash -c 'cd /etc; ls; $SHELL' команда, которую я только что составил в качестве примера; вот что она делает:
  • bash -c говорит, что это команда bash 'c'
  • cd /etc = 'c'изменить 'директорию в путь "/etc"
  • ls = 'я не содержимое этого каталога
  • $SHELL = этот загадочный лакомый кусочек необходим для того, чтобы оболочка оставалась открытой, чтобы вы могли с ней работать. Если вы хотите, чтобы оболочка открылась, запустите свою команду, затем закройте, просто удалите эту часть. Я, однако, хочу, чтобы вкладка оставалась открытой, чтобы я мог творить волшебство программирования. :)
  • затем мы снова начинаем с --tab часть для создания вкладки 2, затем снова для вкладки 3. Настраивайте так, как вам заблагорассудится.

Скриншот:

enter image description here

Довольно просто-

#!/bin/bash/etc/init.d/ccpd status

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

#!/bin/bashgnome-terminal -e "/etc/init.d/ccpd status"  --window-with-profile=NAMEOFTHEPROFILE

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

Здесь "NAMEOFTHEPROFILE" должно быть заменено именем профиля, который "Удерживает терминал при завершении команды".

enter image description here

enter image description here

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

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

Вызовите свой скрипт с помощью необязательных аргументов "x-terminal-emulator -e /path/to/script hacky_function здесь".

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

Я должен связать несколько вкладок таким образом, избегая при этом предупреждений, вызванных использованием --command, который скоро устареет:

gnome-terminal\    --tab\        --title="TAB 1" -- bash -c "cd ~; ls; $SHELL"gnome-terminal\    --tab\        --title="TAB 2" -- bash -c "cd ~/Desktop; ls; $SHELL"\

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

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

dellstart.gif

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

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

Программа на python:

#!/usr/bin/env python# -*- coding: utf-8 -*-#==============================================================================##       dellstart - Autostart GUI applications on Dell Fileserver##=============================================================================='''CALL:   dellstartREQUIRES:   sudo apt install xdotool    '''from __future__ import print_function           # Must be first importimport osimport timeBASHRC_TIME = 2                                 # Seconds to load ~/.bashrcWINDOW_TIME = .5                                # Secpmds fpr window to appearcommands = [ '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 resultdef 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 PIDdef 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 windowsdef 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_filesif __name__ == "__main__":    process_commands(commands)# end of dellstart

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

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

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

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