Reputation: 741
I am trying to get the exit code of a command launched via x-terminal-emulator -e
. Using this command, it simply opens a new terminal window and passes it sh -c
with the command that you want to be executed within the new terminal window. I then use a combination of ps ax, grep, xargs
& cut
to get the PID of the running process.
#!/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"
However, when I utilize the command wait
to wait for the PID to finish running so that I can get the exit code of the command, wait
returns:
pid #### is not a child of this shell
Is there a way where I can both wait for the PID to finish, then grab its exit code from a process not spawned under the parent shell?
Upvotes: 0
Views: 1284
Reputation: 741
After a bit of trial and error and some research, I have come up with a solution.
My solution involves the following:
$?
output from within the new terminal window that was spawned from x-terminal-emulator
to a temporary file utilizing mktemp
.until
conditional structure to wait until that temporary file is not empty.cat
the contents of the file and store it within a variable. Then, echo
the results.#!/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"
Upvotes: 1
Reputation: 3441
Why would you use another terminal and not create a child process? It's much more cleaner IMHO. This way you're able to use the wait command:
function i_exit {
($1) &
wait $!
return $?
}
i_exit "true"
echo $?
i_exit "false"
echo $?
i_exit "true && true"
echo $?
i_exit "true && false"
echo $?
You create a background process using "&". The PID created is stored in $! and when the child exits, you can return the value with $?. This is catchable out of the function with the same variable. The code above outputs:
$ ./test.sh
0
1
0
0
No ps aux | grep whatever
needed!
EDIT: Of course you can execute things in a terminal if you really wanted to. The following script does just that. I dont have xfce, but you can replace "xterm" with "x-terminal-emulator".
#! /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 $?
Upvotes: 1
Reputation: 69
Is there a reason to launch your command in another xterm? your script seems to be sequential, so perhaps this solution could be acceptable?
#!/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"
Upvotes: 1