Как мне получить код выхода PID вне родительской оболочки? - PullRequest
0 голосов
/ 25 января 2019

Фон

Я пытаюсь получить код завершения команды, запущенной через x-terminal-emulator -e.Используя эту команду, он просто открывает новое окно терминала и передает его sh -c с командой, которую вы хотите выполнить в новом окне терминала.Затем я использую комбинацию ps ax, grep, xargs & cut, чтобы получить PID запущенного процесса.

??‍?tester.sh

#!/bin/bash

execute() {

    local -r CMDS="$1"
    local exitCode=0
    local cmdsPID=""

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Execute a command within a 
    # a new 'x-terminal-emulator' window.

    x-terminal-emulator -e "$CMDS" &> /dev/null

    # Get the PID of the process spawned by
    # 'x-terminal-emulator'.

    cmdsPID="$(ps ax | grep "sh -c $CMDS" | xargs | cut -d ' ' -f 1)"

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Wait for the commands to no longer be executing
    # in the background, and then get their exit code.

    wait "$cmdsPID" &> /dev/null
    exitCode=$?

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Print output based on what happened.

    echo "$exitCode"    

}

execute "apt update && apt upgrade -y && apt full-upgrade -y && apt autoremove -y && apt clean"

⚠️ Ошибка

Однако, когда я использую команду wait, чтобы дождаться окончания запуска PID и получить код завершения команды, wait возвращает:

pid #### is not a child of this shell

Есть ли способ, в котором я могу оба дождаться завершения PID, а затем получить его код выхода из процесса, не порожденного родительской оболочкой?

Ответы [ 3 ]

0 голосов
/ 25 января 2019

После небольшого количества проб и ошибок и некоторых исследований я нашел решение.

Мое решение включает следующее:

  1. Использование перенаправления вывода $? из нового окна терминала, порожденного из x-terminal-emulator, во временный файл с использованием mktemp.
  2. Затем, используя условную структуру until, дождемся, пока этот временный файл не станет пустым.
  3. Когда временный файл не пуст, я могу cat содержимое файла и сохранить его в переменной. Затем echo результаты.

??‍?tester.sh (Refactored)

#!/bin/bash

execute() {

    local -r CMDS="$1"

    local -r EXIT_STATUS_FILE="$(mktemp /tmp/XXXXX)"

    local exitCode=0
    local cmdsPID=""

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Execute a command within a 
    # a new 'x-terminal-emulator' window.

    x-terminal-emulator -e "($CMDS) ; echo \$? > $EXIT_STATUS_FILE" \
        &> /dev/null

    # Get the PID of the process spawned by
    # 'x-terminal-emulator'.

    cmdsPID="$(ps ax | grep -v "grep" | grep -v "S+" | grep "sh -c" | grep "$CMDS" | xargs | cut -d ' ' -f 1)"

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Wait for the commands to no longer be executing
    # in the background, and then get their exit code.

    until [ -s "$EXIT_STATUS_FILE" ];
    do
        sleep 1
    done

    exitCode="$(cat "$EXIT_STATUS_FILE")"

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Print output based on what happened.

    echo "$exitCode"

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Remove temporary file.

    rm -rf "$EXIT_STATUS_FILE"  

}

execute \
  "apt update && apt upgrade -y && apt full-upgrade -y && apt autoremove -y && apt clean"
0 голосов
/ 26 января 2019

Зачем вам использовать другой терминал, а не создавать дочерний процесс?Это намного чище ИМХО.Таким образом, вы можете использовать команду ожидания:

function i_exit {
        ($1) &
        wait $!
        return $?
}

i_exit "true"
echo $?
i_exit "false"
echo $?
i_exit "true && true"
echo $?
i_exit "true && false"
echo $?

Вы создаете фоновый процесс, используя «&».Созданный PID хранится в $!и когда ребенок выходит, вы можете вернуть значение с помощью $ ?.Это можно отследить из функции с той же переменной.Код выше выводит:

$ ./test.sh 
0
1
0
0

Нет ps aux | grep whatever необходимо!

РЕДАКТИРОВАТЬ: Конечно, вы можете выполнять вещи в терминале, если вы действительно этого хотите.Следующий скрипт делает именно это.У меня нет xfce, но вы можете заменить «xterm» на «x-терминал-эмулятор».

#! /bin/bash

function i_exit {
        (xterm -e "$1") &
        wait $!
        return $?
}

# Waits 5 seconds
i_exit "true && echo 'Test 1' && sleep 5s"
echo $?
# Exits immediately
i_exit "false && echo 'Test 2' && sleep 5s"
echo $?
0 голосов
/ 25 января 2019

Есть ли причина для запуска вашей команды в другом xterm?Ваш сценарий выглядит последовательным, поэтому, возможно, это решение может быть приемлемым?

#!/bin/bash

execute() {

    local -r CMDS="$1"
    local exitCode=0
    local cmdsPID=""

    output=`$CMDS > /dev/null`
    exitCode=$?
    echo $exitCode    
}
execute "apt update && apt upgrade -y && apt full-upgrade -y && apt autoremove -y && apt clean"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...