Issue
I am implementing custom gitlab-runer executor. Gitlab sends multiple scripts to execute in order, and want to execute them in the same shell session. However, my wrapper script is executed multiple times.
While I could do bash -s <script_from_gitlab.sh
this will execute multiple scripts in a new environment. I would want to keep like a "bash service" running with an open input and output, run a command, then when a command is finished collect the output and display it, all while preserving the environment. This is every similar to Jupiter notebooks in python.
How to implement such "persistent bash session" and to execute one command in that session and collect it output in non-interactive fashion?
My only idea is to separate output by uuid:
#!/bin/bash
prepare() {
# runs a bash in the background waiting for commands
mkfifo /tmp/fifoin /tmp/fifoout
bash -s </tmp/fifoin >/tmp/fifoout &
echo $! > /tmp/bashpid
}
run() {
mark=d1c21272-4055-4cd4-a0d4-3462e7d29373
{
# executes script
cat "$1"
echo "$mark"
} > /tmp/fifoin &
while IFS= read -r line; do
if [[ "$line" == "$mark" ]]; then
break
fi
printf "%s\n" "$line"
done
}
cleanup() {
pid=$(</tmp/bashpid)
kill "$pid"
tail -f --pid "$pid"
}
# executed with arguments: "cleanup" "run thiscript" "run thatscript" "cleanup" in order
"$1" "$2"
However, this feels like a workaround, especially with the "mark" to get if the script finished execution or not. Is there a different solution?
In real life, the commands are run by Nomad scheduler. It's the same, just bash -s
is executed with nomad exec <allocid> bash -s
.
Solution
This is an attempt, hope it can be adapted to meet your requirements :
#!/bin/sh
input=/tmp/pipe-input
output=/tmp/pipe-output
# Wait for commands from $input and send results to $output
server(){
rm -f $input $output
mkfifo $input $output
while true; do
echo "Hello from server." >&2
eval "$(cat $input)" > $output
done
}
client(){
cat > $input; cat $output
}
# Send commands to server every second.
test-client(){
for i in {1..6}; do
client <<< 'echo $(date +%T) server hostname=$(hostname), server bash PID=$$'
sleep 1
done
client <<< 'exit'
}
"$@"
In one window, run
bash test.sh server
In another window, run
bash test.sh test-client
I think the usage of eval
is "tolerable" as you are in control of the commands to run.
Answered By - Philippe Answer Checked By - Mary Flores (WPSolving Volunteer)