Modify a variable in a running Bash script





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







1















I have a bash script which processes several years of data, therefore the script can take a week to finish.
To speed up the process, I use multithreading, by running several instances in parallel (each instance = 1 day of data). Each instance occupies 1 CPU, so I can run as many instances as CPUs available. As I am running the process in a powerful server which I am sharing with others, at some time I may have more or less CPUs available.
My current script is:



#!/bin/bash
function waitpid {
#Gather the gLABs PID background processes (Maximum processes in
#background as number of CPUs)
NUMPIDS=`jobs -p|awk 'END {print NR}'`
#A while is set because there seems to be a bug in bash that makes
#sometimes the "wait -n" command
#exit even if none of provided PIDs have finished. If this happens,
#the while loops forces the
#script to wait until one of the processes is truly finished
while [ ${NUMPIDS} -ge ${NUMCPUS} ]
do
#Wait for gLAB processes to finish
PIDS="`jobs -p|awk -v ORS=" " '{print}'`"
wait -n ${PIDS} >/dev/null 2>/dev/null
NUMPIDS=`jobs -p|awk 'END {print NR}'`
done
}
NUMPCUS=10
for(...) #Loop for each day
do
day=... #Set current day variable
#Command to execute, put in background
gLAB_linux -input ${day}folder/${day}.input -output ${day)outfolder/${day}.output &
#Wait for any process to finish if NUMCPUS number of processes are running in background
waitpid
done


Therefore, my question is: if this script is running, is there any way I can change the variable NUMCPUS to any value (for instance NUMCPUS=23) without stopping the script?.
If possible, I would prefer a method that does not involve reading or writing to file (I like to reduce temporary files to 0 if possible).
I don't mind if it is a "hackish" process, such as the method described in this answer. Actually, I tried in gdb similar commands as in that answer but it didn't work, I had the following errors in gdb (and also made the process to crash):



(gdb) attach 23865
(gdb) call bind_variable("NUMCPUS",11,0)
'bind_variable' has unknown return type; cast the call to its declared return type
(gdb) call (int)bind_variable("NUMCPUS",11,0)
Program received signal SIGSEGV, Segmentation fault


EDIT1: Some comments to the script:




  • gLAB_linux is a single core processing program and is not aware of NUMCPUS variable

  • Each gLAB_linux execution takes around 5 hours to finish, therefore the bash script is most of the time sleeping inside the wait -n.

  • NUMCPUS must be a local variable for the script, as there may be another script like this one running in parallel (changing only the parameters given to gLAB_linux). Therefore NUMCPUS can't be an environment variable.

  • The only process accessing NUMCPUS is the bash script


EDIT2: After @Kamil answer, I add my proposal for reading from a file the number of CPUs



function waitpid {
#Look if there is a file with new number of CPUs
if [ -s "/tmp/numCPUs_$$.txt" ]
then
TMPVAR=$(awk '$1>0 {print "%d",$1} {exit}' "/tmp/numCPUs_$$.txt")
if [ -n "${TMPVAR}" ]
then
NUMCPUS=${TMPVAR}
echo "NUMCPUS=${TMPVAR}"
fi
rm -f "/tmp/numCPUs_$$.txt"
fi

#Gather the gLABs PID background processes (Maximum processes in
#background as number of CPUs)
NUMPIDS=`jobs -p|awk 'END {print NR}'`
#A while is set because there seems to be a bug in bash that makes
#sometimes the "wait -n" command
#exit even if none of provided PIDs have finished. If this happens,
#the while loops forces the
#script to wait until one of the processes is truly finished
while [ ${NUMPIDS} -ge ${NUMCPUS} ]
do
#Wait for gLAB processes to finish
PIDS="`jobs -p|awk -v ORS=" " '{print}'`"
wait -n ${PIDS} >/dev/null 2>/dev/null
NUMPIDS=`jobs -p|awk 'END {print NR}'`
done
}









share|improve this question




















  • 2





    See the --limit argument of GNU parallel.

    – choroba
    Nov 22 '18 at 11:46











  • what about control with signal?

    – georgexsh
    Nov 22 '18 at 11:58











  • Each instance will have different input and output files and folder, so I can't use parallel bash command. I edited the question. With signals, the problem is that I can't set an arbitrary value to the variable

    – AwkMan
    Nov 22 '18 at 12:00








  • 2





    @AwkMan read the variable from a file is much more reliable than hack with gdb, but I guess you are doing this for fun, than good luck! btw parallel could read cmd lines from stdin.

    – georgexsh
    Nov 22 '18 at 12:18








  • 1





    @AwkMan parallel supports read proc num from a file.

    – georgexsh
    Nov 22 '18 at 15:10


















1















I have a bash script which processes several years of data, therefore the script can take a week to finish.
To speed up the process, I use multithreading, by running several instances in parallel (each instance = 1 day of data). Each instance occupies 1 CPU, so I can run as many instances as CPUs available. As I am running the process in a powerful server which I am sharing with others, at some time I may have more or less CPUs available.
My current script is:



#!/bin/bash
function waitpid {
#Gather the gLABs PID background processes (Maximum processes in
#background as number of CPUs)
NUMPIDS=`jobs -p|awk 'END {print NR}'`
#A while is set because there seems to be a bug in bash that makes
#sometimes the "wait -n" command
#exit even if none of provided PIDs have finished. If this happens,
#the while loops forces the
#script to wait until one of the processes is truly finished
while [ ${NUMPIDS} -ge ${NUMCPUS} ]
do
#Wait for gLAB processes to finish
PIDS="`jobs -p|awk -v ORS=" " '{print}'`"
wait -n ${PIDS} >/dev/null 2>/dev/null
NUMPIDS=`jobs -p|awk 'END {print NR}'`
done
}
NUMPCUS=10
for(...) #Loop for each day
do
day=... #Set current day variable
#Command to execute, put in background
gLAB_linux -input ${day}folder/${day}.input -output ${day)outfolder/${day}.output &
#Wait for any process to finish if NUMCPUS number of processes are running in background
waitpid
done


Therefore, my question is: if this script is running, is there any way I can change the variable NUMCPUS to any value (for instance NUMCPUS=23) without stopping the script?.
If possible, I would prefer a method that does not involve reading or writing to file (I like to reduce temporary files to 0 if possible).
I don't mind if it is a "hackish" process, such as the method described in this answer. Actually, I tried in gdb similar commands as in that answer but it didn't work, I had the following errors in gdb (and also made the process to crash):



(gdb) attach 23865
(gdb) call bind_variable("NUMCPUS",11,0)
'bind_variable' has unknown return type; cast the call to its declared return type
(gdb) call (int)bind_variable("NUMCPUS",11,0)
Program received signal SIGSEGV, Segmentation fault


EDIT1: Some comments to the script:




  • gLAB_linux is a single core processing program and is not aware of NUMCPUS variable

  • Each gLAB_linux execution takes around 5 hours to finish, therefore the bash script is most of the time sleeping inside the wait -n.

  • NUMCPUS must be a local variable for the script, as there may be another script like this one running in parallel (changing only the parameters given to gLAB_linux). Therefore NUMCPUS can't be an environment variable.

  • The only process accessing NUMCPUS is the bash script


EDIT2: After @Kamil answer, I add my proposal for reading from a file the number of CPUs



function waitpid {
#Look if there is a file with new number of CPUs
if [ -s "/tmp/numCPUs_$$.txt" ]
then
TMPVAR=$(awk '$1>0 {print "%d",$1} {exit}' "/tmp/numCPUs_$$.txt")
if [ -n "${TMPVAR}" ]
then
NUMCPUS=${TMPVAR}
echo "NUMCPUS=${TMPVAR}"
fi
rm -f "/tmp/numCPUs_$$.txt"
fi

#Gather the gLABs PID background processes (Maximum processes in
#background as number of CPUs)
NUMPIDS=`jobs -p|awk 'END {print NR}'`
#A while is set because there seems to be a bug in bash that makes
#sometimes the "wait -n" command
#exit even if none of provided PIDs have finished. If this happens,
#the while loops forces the
#script to wait until one of the processes is truly finished
while [ ${NUMPIDS} -ge ${NUMCPUS} ]
do
#Wait for gLAB processes to finish
PIDS="`jobs -p|awk -v ORS=" " '{print}'`"
wait -n ${PIDS} >/dev/null 2>/dev/null
NUMPIDS=`jobs -p|awk 'END {print NR}'`
done
}









share|improve this question




















  • 2





    See the --limit argument of GNU parallel.

    – choroba
    Nov 22 '18 at 11:46











  • what about control with signal?

    – georgexsh
    Nov 22 '18 at 11:58











  • Each instance will have different input and output files and folder, so I can't use parallel bash command. I edited the question. With signals, the problem is that I can't set an arbitrary value to the variable

    – AwkMan
    Nov 22 '18 at 12:00








  • 2





    @AwkMan read the variable from a file is much more reliable than hack with gdb, but I guess you are doing this for fun, than good luck! btw parallel could read cmd lines from stdin.

    – georgexsh
    Nov 22 '18 at 12:18








  • 1





    @AwkMan parallel supports read proc num from a file.

    – georgexsh
    Nov 22 '18 at 15:10














1












1








1


1






I have a bash script which processes several years of data, therefore the script can take a week to finish.
To speed up the process, I use multithreading, by running several instances in parallel (each instance = 1 day of data). Each instance occupies 1 CPU, so I can run as many instances as CPUs available. As I am running the process in a powerful server which I am sharing with others, at some time I may have more or less CPUs available.
My current script is:



#!/bin/bash
function waitpid {
#Gather the gLABs PID background processes (Maximum processes in
#background as number of CPUs)
NUMPIDS=`jobs -p|awk 'END {print NR}'`
#A while is set because there seems to be a bug in bash that makes
#sometimes the "wait -n" command
#exit even if none of provided PIDs have finished. If this happens,
#the while loops forces the
#script to wait until one of the processes is truly finished
while [ ${NUMPIDS} -ge ${NUMCPUS} ]
do
#Wait for gLAB processes to finish
PIDS="`jobs -p|awk -v ORS=" " '{print}'`"
wait -n ${PIDS} >/dev/null 2>/dev/null
NUMPIDS=`jobs -p|awk 'END {print NR}'`
done
}
NUMPCUS=10
for(...) #Loop for each day
do
day=... #Set current day variable
#Command to execute, put in background
gLAB_linux -input ${day}folder/${day}.input -output ${day)outfolder/${day}.output &
#Wait for any process to finish if NUMCPUS number of processes are running in background
waitpid
done


Therefore, my question is: if this script is running, is there any way I can change the variable NUMCPUS to any value (for instance NUMCPUS=23) without stopping the script?.
If possible, I would prefer a method that does not involve reading or writing to file (I like to reduce temporary files to 0 if possible).
I don't mind if it is a "hackish" process, such as the method described in this answer. Actually, I tried in gdb similar commands as in that answer but it didn't work, I had the following errors in gdb (and also made the process to crash):



(gdb) attach 23865
(gdb) call bind_variable("NUMCPUS",11,0)
'bind_variable' has unknown return type; cast the call to its declared return type
(gdb) call (int)bind_variable("NUMCPUS",11,0)
Program received signal SIGSEGV, Segmentation fault


EDIT1: Some comments to the script:




  • gLAB_linux is a single core processing program and is not aware of NUMCPUS variable

  • Each gLAB_linux execution takes around 5 hours to finish, therefore the bash script is most of the time sleeping inside the wait -n.

  • NUMCPUS must be a local variable for the script, as there may be another script like this one running in parallel (changing only the parameters given to gLAB_linux). Therefore NUMCPUS can't be an environment variable.

  • The only process accessing NUMCPUS is the bash script


EDIT2: After @Kamil answer, I add my proposal for reading from a file the number of CPUs



function waitpid {
#Look if there is a file with new number of CPUs
if [ -s "/tmp/numCPUs_$$.txt" ]
then
TMPVAR=$(awk '$1>0 {print "%d",$1} {exit}' "/tmp/numCPUs_$$.txt")
if [ -n "${TMPVAR}" ]
then
NUMCPUS=${TMPVAR}
echo "NUMCPUS=${TMPVAR}"
fi
rm -f "/tmp/numCPUs_$$.txt"
fi

#Gather the gLABs PID background processes (Maximum processes in
#background as number of CPUs)
NUMPIDS=`jobs -p|awk 'END {print NR}'`
#A while is set because there seems to be a bug in bash that makes
#sometimes the "wait -n" command
#exit even if none of provided PIDs have finished. If this happens,
#the while loops forces the
#script to wait until one of the processes is truly finished
while [ ${NUMPIDS} -ge ${NUMCPUS} ]
do
#Wait for gLAB processes to finish
PIDS="`jobs -p|awk -v ORS=" " '{print}'`"
wait -n ${PIDS} >/dev/null 2>/dev/null
NUMPIDS=`jobs -p|awk 'END {print NR}'`
done
}









share|improve this question
















I have a bash script which processes several years of data, therefore the script can take a week to finish.
To speed up the process, I use multithreading, by running several instances in parallel (each instance = 1 day of data). Each instance occupies 1 CPU, so I can run as many instances as CPUs available. As I am running the process in a powerful server which I am sharing with others, at some time I may have more or less CPUs available.
My current script is:



#!/bin/bash
function waitpid {
#Gather the gLABs PID background processes (Maximum processes in
#background as number of CPUs)
NUMPIDS=`jobs -p|awk 'END {print NR}'`
#A while is set because there seems to be a bug in bash that makes
#sometimes the "wait -n" command
#exit even if none of provided PIDs have finished. If this happens,
#the while loops forces the
#script to wait until one of the processes is truly finished
while [ ${NUMPIDS} -ge ${NUMCPUS} ]
do
#Wait for gLAB processes to finish
PIDS="`jobs -p|awk -v ORS=" " '{print}'`"
wait -n ${PIDS} >/dev/null 2>/dev/null
NUMPIDS=`jobs -p|awk 'END {print NR}'`
done
}
NUMPCUS=10
for(...) #Loop for each day
do
day=... #Set current day variable
#Command to execute, put in background
gLAB_linux -input ${day}folder/${day}.input -output ${day)outfolder/${day}.output &
#Wait for any process to finish if NUMCPUS number of processes are running in background
waitpid
done


Therefore, my question is: if this script is running, is there any way I can change the variable NUMCPUS to any value (for instance NUMCPUS=23) without stopping the script?.
If possible, I would prefer a method that does not involve reading or writing to file (I like to reduce temporary files to 0 if possible).
I don't mind if it is a "hackish" process, such as the method described in this answer. Actually, I tried in gdb similar commands as in that answer but it didn't work, I had the following errors in gdb (and also made the process to crash):



(gdb) attach 23865
(gdb) call bind_variable("NUMCPUS",11,0)
'bind_variable' has unknown return type; cast the call to its declared return type
(gdb) call (int)bind_variable("NUMCPUS",11,0)
Program received signal SIGSEGV, Segmentation fault


EDIT1: Some comments to the script:




  • gLAB_linux is a single core processing program and is not aware of NUMCPUS variable

  • Each gLAB_linux execution takes around 5 hours to finish, therefore the bash script is most of the time sleeping inside the wait -n.

  • NUMCPUS must be a local variable for the script, as there may be another script like this one running in parallel (changing only the parameters given to gLAB_linux). Therefore NUMCPUS can't be an environment variable.

  • The only process accessing NUMCPUS is the bash script


EDIT2: After @Kamil answer, I add my proposal for reading from a file the number of CPUs



function waitpid {
#Look if there is a file with new number of CPUs
if [ -s "/tmp/numCPUs_$$.txt" ]
then
TMPVAR=$(awk '$1>0 {print "%d",$1} {exit}' "/tmp/numCPUs_$$.txt")
if [ -n "${TMPVAR}" ]
then
NUMCPUS=${TMPVAR}
echo "NUMCPUS=${TMPVAR}"
fi
rm -f "/tmp/numCPUs_$$.txt"
fi

#Gather the gLABs PID background processes (Maximum processes in
#background as number of CPUs)
NUMPIDS=`jobs -p|awk 'END {print NR}'`
#A while is set because there seems to be a bug in bash that makes
#sometimes the "wait -n" command
#exit even if none of provided PIDs have finished. If this happens,
#the while loops forces the
#script to wait until one of the processes is truly finished
while [ ${NUMPIDS} -ge ${NUMCPUS} ]
do
#Wait for gLAB processes to finish
PIDS="`jobs -p|awk -v ORS=" " '{print}'`"
wait -n ${PIDS} >/dev/null 2>/dev/null
NUMPIDS=`jobs -p|awk 'END {print NR}'`
done
}






bash gdb






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 22 '18 at 14:08







AwkMan

















asked Nov 22 '18 at 11:40









AwkManAwkMan

540415




540415








  • 2





    See the --limit argument of GNU parallel.

    – choroba
    Nov 22 '18 at 11:46











  • what about control with signal?

    – georgexsh
    Nov 22 '18 at 11:58











  • Each instance will have different input and output files and folder, so I can't use parallel bash command. I edited the question. With signals, the problem is that I can't set an arbitrary value to the variable

    – AwkMan
    Nov 22 '18 at 12:00








  • 2





    @AwkMan read the variable from a file is much more reliable than hack with gdb, but I guess you are doing this for fun, than good luck! btw parallel could read cmd lines from stdin.

    – georgexsh
    Nov 22 '18 at 12:18








  • 1





    @AwkMan parallel supports read proc num from a file.

    – georgexsh
    Nov 22 '18 at 15:10














  • 2





    See the --limit argument of GNU parallel.

    – choroba
    Nov 22 '18 at 11:46











  • what about control with signal?

    – georgexsh
    Nov 22 '18 at 11:58











  • Each instance will have different input and output files and folder, so I can't use parallel bash command. I edited the question. With signals, the problem is that I can't set an arbitrary value to the variable

    – AwkMan
    Nov 22 '18 at 12:00








  • 2





    @AwkMan read the variable from a file is much more reliable than hack with gdb, but I guess you are doing this for fun, than good luck! btw parallel could read cmd lines from stdin.

    – georgexsh
    Nov 22 '18 at 12:18








  • 1





    @AwkMan parallel supports read proc num from a file.

    – georgexsh
    Nov 22 '18 at 15:10








2




2





See the --limit argument of GNU parallel.

– choroba
Nov 22 '18 at 11:46





See the --limit argument of GNU parallel.

– choroba
Nov 22 '18 at 11:46













what about control with signal?

– georgexsh
Nov 22 '18 at 11:58





what about control with signal?

– georgexsh
Nov 22 '18 at 11:58













Each instance will have different input and output files and folder, so I can't use parallel bash command. I edited the question. With signals, the problem is that I can't set an arbitrary value to the variable

– AwkMan
Nov 22 '18 at 12:00







Each instance will have different input and output files and folder, so I can't use parallel bash command. I edited the question. With signals, the problem is that I can't set an arbitrary value to the variable

– AwkMan
Nov 22 '18 at 12:00






2




2





@AwkMan read the variable from a file is much more reliable than hack with gdb, but I guess you are doing this for fun, than good luck! btw parallel could read cmd lines from stdin.

– georgexsh
Nov 22 '18 at 12:18







@AwkMan read the variable from a file is much more reliable than hack with gdb, but I guess you are doing this for fun, than good luck! btw parallel could read cmd lines from stdin.

– georgexsh
Nov 22 '18 at 12:18






1




1





@AwkMan parallel supports read proc num from a file.

– georgexsh
Nov 22 '18 at 15:10





@AwkMan parallel supports read proc num from a file.

– georgexsh
Nov 22 '18 at 15:10












2 Answers
2






active

oldest

votes


















2














The best would be to modify the bash script so it is aware that you change the value. Modifying an environment variable from inside a gdb session - that's just intrusive and mostly discards other developers work.



Below I use a file named /tmp/signal_num_cpus. If the file doesn't exist, the script uses the NUMCPUS value. If the file does exists, it reads it content and updates the number of NUMCPUS accordingly and then prints some notification that the numcpus was changed to the file. If the file does exists and does not contain a valid number (for example in predefined range or smth) it prints some error message into the file. The other side is notified that everything is ok or something bad happened



#!/bin/bash

is_not_number() {
(( $1 != $1 )) 2>/dev/null
}

# global variable to hold the number of cpus with a default value
NUMCPUS=${NUMCPUS:=5}
# this will ideally execute on each access to NUMCPUS variable
# depending on content
get_num_cpus() {
# I tell others that NUMCPUS is a global variable and i expect it here
declare -g NUMCPUS
# I will use this filename to communicate
declare -r file="/tmp/signal_num_cpus"
# If the file exists and is a fifo...
if [ -p "$file" ]; then
local tmp
# get file contents
tmp=$(<"$file")
if [ -z "$tmp" ]; then
#empty is ignored
:;
elif is_not_number "$tmp"; then
echo "Error reading a number from $file" >&2
echo "error: not a number, please give me a number!" > "$file"
else
# If it is ok, update the NUMCPUS value
NUMCPUS=$tmp
echo "ok $NUMCPUS" > "$file" # this will block until other side starts reading
fi
fi
# last but not least, let's output it
echo "$NUMCPUS"
}

# code duplication is the worst (ok, sometimes except for databases frameworks)
get_num_bg_jobs() {
jobs -p | wc -l
}

waitpid() {
while
(( $(get_num_bg_jobs) >= $(get_num_cpus) ))
do
wait -n
done
}

# rest of the script

NUMPCUS=10
for(...) #Loop for each day
do
day=... #Set current day variable
#Command to execute, put in background
gLAB_linux -input "${day}folder/${day}.input" -output "${day)outfolder/${day}.output" &
#Wait for any process to finish if NUMCPUS number of processes are running in background
waitpid
done


And changing the value script could look like this:



#!/bin/bash

# shared context between scripts
declare -r file="/tmp/signal_num_cpus"

mkfifo "$file"

echo 1 > "$file" # this will block until other side will start reading

IFS= read -r line < "$file"

case "$line" in
ok*)
read _ numcpus <<<"$line"
echo "the script changed the number of numcpus to $numcpus"
;;
*)
echo "the script errored with $error"
;;
esac

rm "$file"


Marks:




  • the correct way to define a function is func() { :; } Using function func { } is somthing taken from ksh and is supported as an extension. Use func() {}

  • It is nice to use arithmetic expansion (( ... )) for number comparisons nad handling.

  • Using backticks ` for command substitution $( ... ) is deprecated.






share|improve this answer
























  • Your method for using a file I find it way too complicated, specially regardind the use of "declare" and mkfifo. Maybe because I forgot to clarify some things in my questions (see edit in my question). I will edit (again) my question for adding my proposal

    – AwkMan
    Nov 22 '18 at 13:41











  • declare is just there to simplify reading, you can toss them all out. mkfifo is used because it's easier to synchronize processes using them, you can use normal file + flock or disregard locking altogether. If you search for multiple instances of the script to run, append unique name to the config-filename in each script, for example by using $$.

    – Kamil Cuk
    Nov 22 '18 at 13:49



















1














Chapter 7.1 of GNU Parallel 2018 covers how to change the number of threads to use while running https://zenodo.org/record/1146014



echo 50% > my_jobs
/usr/bin/time parallel -N0 --jobs my_jobs sleep 1 :::: num128 &
sleep 1
echo 0 > my_jobs
wait


So you simply put the argument for --jobs into my_jobs and GNU Parallel will read this after each completed job.






share|improve this answer
























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53430218%2fmodify-a-variable-in-a-running-bash-script%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














    The best would be to modify the bash script so it is aware that you change the value. Modifying an environment variable from inside a gdb session - that's just intrusive and mostly discards other developers work.



    Below I use a file named /tmp/signal_num_cpus. If the file doesn't exist, the script uses the NUMCPUS value. If the file does exists, it reads it content and updates the number of NUMCPUS accordingly and then prints some notification that the numcpus was changed to the file. If the file does exists and does not contain a valid number (for example in predefined range or smth) it prints some error message into the file. The other side is notified that everything is ok or something bad happened



    #!/bin/bash

    is_not_number() {
    (( $1 != $1 )) 2>/dev/null
    }

    # global variable to hold the number of cpus with a default value
    NUMCPUS=${NUMCPUS:=5}
    # this will ideally execute on each access to NUMCPUS variable
    # depending on content
    get_num_cpus() {
    # I tell others that NUMCPUS is a global variable and i expect it here
    declare -g NUMCPUS
    # I will use this filename to communicate
    declare -r file="/tmp/signal_num_cpus"
    # If the file exists and is a fifo...
    if [ -p "$file" ]; then
    local tmp
    # get file contents
    tmp=$(<"$file")
    if [ -z "$tmp" ]; then
    #empty is ignored
    :;
    elif is_not_number "$tmp"; then
    echo "Error reading a number from $file" >&2
    echo "error: not a number, please give me a number!" > "$file"
    else
    # If it is ok, update the NUMCPUS value
    NUMCPUS=$tmp
    echo "ok $NUMCPUS" > "$file" # this will block until other side starts reading
    fi
    fi
    # last but not least, let's output it
    echo "$NUMCPUS"
    }

    # code duplication is the worst (ok, sometimes except for databases frameworks)
    get_num_bg_jobs() {
    jobs -p | wc -l
    }

    waitpid() {
    while
    (( $(get_num_bg_jobs) >= $(get_num_cpus) ))
    do
    wait -n
    done
    }

    # rest of the script

    NUMPCUS=10
    for(...) #Loop for each day
    do
    day=... #Set current day variable
    #Command to execute, put in background
    gLAB_linux -input "${day}folder/${day}.input" -output "${day)outfolder/${day}.output" &
    #Wait for any process to finish if NUMCPUS number of processes are running in background
    waitpid
    done


    And changing the value script could look like this:



    #!/bin/bash

    # shared context between scripts
    declare -r file="/tmp/signal_num_cpus"

    mkfifo "$file"

    echo 1 > "$file" # this will block until other side will start reading

    IFS= read -r line < "$file"

    case "$line" in
    ok*)
    read _ numcpus <<<"$line"
    echo "the script changed the number of numcpus to $numcpus"
    ;;
    *)
    echo "the script errored with $error"
    ;;
    esac

    rm "$file"


    Marks:




    • the correct way to define a function is func() { :; } Using function func { } is somthing taken from ksh and is supported as an extension. Use func() {}

    • It is nice to use arithmetic expansion (( ... )) for number comparisons nad handling.

    • Using backticks ` for command substitution $( ... ) is deprecated.






    share|improve this answer
























    • Your method for using a file I find it way too complicated, specially regardind the use of "declare" and mkfifo. Maybe because I forgot to clarify some things in my questions (see edit in my question). I will edit (again) my question for adding my proposal

      – AwkMan
      Nov 22 '18 at 13:41











    • declare is just there to simplify reading, you can toss them all out. mkfifo is used because it's easier to synchronize processes using them, you can use normal file + flock or disregard locking altogether. If you search for multiple instances of the script to run, append unique name to the config-filename in each script, for example by using $$.

      – Kamil Cuk
      Nov 22 '18 at 13:49
















    2














    The best would be to modify the bash script so it is aware that you change the value. Modifying an environment variable from inside a gdb session - that's just intrusive and mostly discards other developers work.



    Below I use a file named /tmp/signal_num_cpus. If the file doesn't exist, the script uses the NUMCPUS value. If the file does exists, it reads it content and updates the number of NUMCPUS accordingly and then prints some notification that the numcpus was changed to the file. If the file does exists and does not contain a valid number (for example in predefined range or smth) it prints some error message into the file. The other side is notified that everything is ok or something bad happened



    #!/bin/bash

    is_not_number() {
    (( $1 != $1 )) 2>/dev/null
    }

    # global variable to hold the number of cpus with a default value
    NUMCPUS=${NUMCPUS:=5}
    # this will ideally execute on each access to NUMCPUS variable
    # depending on content
    get_num_cpus() {
    # I tell others that NUMCPUS is a global variable and i expect it here
    declare -g NUMCPUS
    # I will use this filename to communicate
    declare -r file="/tmp/signal_num_cpus"
    # If the file exists and is a fifo...
    if [ -p "$file" ]; then
    local tmp
    # get file contents
    tmp=$(<"$file")
    if [ -z "$tmp" ]; then
    #empty is ignored
    :;
    elif is_not_number "$tmp"; then
    echo "Error reading a number from $file" >&2
    echo "error: not a number, please give me a number!" > "$file"
    else
    # If it is ok, update the NUMCPUS value
    NUMCPUS=$tmp
    echo "ok $NUMCPUS" > "$file" # this will block until other side starts reading
    fi
    fi
    # last but not least, let's output it
    echo "$NUMCPUS"
    }

    # code duplication is the worst (ok, sometimes except for databases frameworks)
    get_num_bg_jobs() {
    jobs -p | wc -l
    }

    waitpid() {
    while
    (( $(get_num_bg_jobs) >= $(get_num_cpus) ))
    do
    wait -n
    done
    }

    # rest of the script

    NUMPCUS=10
    for(...) #Loop for each day
    do
    day=... #Set current day variable
    #Command to execute, put in background
    gLAB_linux -input "${day}folder/${day}.input" -output "${day)outfolder/${day}.output" &
    #Wait for any process to finish if NUMCPUS number of processes are running in background
    waitpid
    done


    And changing the value script could look like this:



    #!/bin/bash

    # shared context between scripts
    declare -r file="/tmp/signal_num_cpus"

    mkfifo "$file"

    echo 1 > "$file" # this will block until other side will start reading

    IFS= read -r line < "$file"

    case "$line" in
    ok*)
    read _ numcpus <<<"$line"
    echo "the script changed the number of numcpus to $numcpus"
    ;;
    *)
    echo "the script errored with $error"
    ;;
    esac

    rm "$file"


    Marks:




    • the correct way to define a function is func() { :; } Using function func { } is somthing taken from ksh and is supported as an extension. Use func() {}

    • It is nice to use arithmetic expansion (( ... )) for number comparisons nad handling.

    • Using backticks ` for command substitution $( ... ) is deprecated.






    share|improve this answer
























    • Your method for using a file I find it way too complicated, specially regardind the use of "declare" and mkfifo. Maybe because I forgot to clarify some things in my questions (see edit in my question). I will edit (again) my question for adding my proposal

      – AwkMan
      Nov 22 '18 at 13:41











    • declare is just there to simplify reading, you can toss them all out. mkfifo is used because it's easier to synchronize processes using them, you can use normal file + flock or disregard locking altogether. If you search for multiple instances of the script to run, append unique name to the config-filename in each script, for example by using $$.

      – Kamil Cuk
      Nov 22 '18 at 13:49














    2












    2








    2







    The best would be to modify the bash script so it is aware that you change the value. Modifying an environment variable from inside a gdb session - that's just intrusive and mostly discards other developers work.



    Below I use a file named /tmp/signal_num_cpus. If the file doesn't exist, the script uses the NUMCPUS value. If the file does exists, it reads it content and updates the number of NUMCPUS accordingly and then prints some notification that the numcpus was changed to the file. If the file does exists and does not contain a valid number (for example in predefined range or smth) it prints some error message into the file. The other side is notified that everything is ok or something bad happened



    #!/bin/bash

    is_not_number() {
    (( $1 != $1 )) 2>/dev/null
    }

    # global variable to hold the number of cpus with a default value
    NUMCPUS=${NUMCPUS:=5}
    # this will ideally execute on each access to NUMCPUS variable
    # depending on content
    get_num_cpus() {
    # I tell others that NUMCPUS is a global variable and i expect it here
    declare -g NUMCPUS
    # I will use this filename to communicate
    declare -r file="/tmp/signal_num_cpus"
    # If the file exists and is a fifo...
    if [ -p "$file" ]; then
    local tmp
    # get file contents
    tmp=$(<"$file")
    if [ -z "$tmp" ]; then
    #empty is ignored
    :;
    elif is_not_number "$tmp"; then
    echo "Error reading a number from $file" >&2
    echo "error: not a number, please give me a number!" > "$file"
    else
    # If it is ok, update the NUMCPUS value
    NUMCPUS=$tmp
    echo "ok $NUMCPUS" > "$file" # this will block until other side starts reading
    fi
    fi
    # last but not least, let's output it
    echo "$NUMCPUS"
    }

    # code duplication is the worst (ok, sometimes except for databases frameworks)
    get_num_bg_jobs() {
    jobs -p | wc -l
    }

    waitpid() {
    while
    (( $(get_num_bg_jobs) >= $(get_num_cpus) ))
    do
    wait -n
    done
    }

    # rest of the script

    NUMPCUS=10
    for(...) #Loop for each day
    do
    day=... #Set current day variable
    #Command to execute, put in background
    gLAB_linux -input "${day}folder/${day}.input" -output "${day)outfolder/${day}.output" &
    #Wait for any process to finish if NUMCPUS number of processes are running in background
    waitpid
    done


    And changing the value script could look like this:



    #!/bin/bash

    # shared context between scripts
    declare -r file="/tmp/signal_num_cpus"

    mkfifo "$file"

    echo 1 > "$file" # this will block until other side will start reading

    IFS= read -r line < "$file"

    case "$line" in
    ok*)
    read _ numcpus <<<"$line"
    echo "the script changed the number of numcpus to $numcpus"
    ;;
    *)
    echo "the script errored with $error"
    ;;
    esac

    rm "$file"


    Marks:




    • the correct way to define a function is func() { :; } Using function func { } is somthing taken from ksh and is supported as an extension. Use func() {}

    • It is nice to use arithmetic expansion (( ... )) for number comparisons nad handling.

    • Using backticks ` for command substitution $( ... ) is deprecated.






    share|improve this answer













    The best would be to modify the bash script so it is aware that you change the value. Modifying an environment variable from inside a gdb session - that's just intrusive and mostly discards other developers work.



    Below I use a file named /tmp/signal_num_cpus. If the file doesn't exist, the script uses the NUMCPUS value. If the file does exists, it reads it content and updates the number of NUMCPUS accordingly and then prints some notification that the numcpus was changed to the file. If the file does exists and does not contain a valid number (for example in predefined range or smth) it prints some error message into the file. The other side is notified that everything is ok or something bad happened



    #!/bin/bash

    is_not_number() {
    (( $1 != $1 )) 2>/dev/null
    }

    # global variable to hold the number of cpus with a default value
    NUMCPUS=${NUMCPUS:=5}
    # this will ideally execute on each access to NUMCPUS variable
    # depending on content
    get_num_cpus() {
    # I tell others that NUMCPUS is a global variable and i expect it here
    declare -g NUMCPUS
    # I will use this filename to communicate
    declare -r file="/tmp/signal_num_cpus"
    # If the file exists and is a fifo...
    if [ -p "$file" ]; then
    local tmp
    # get file contents
    tmp=$(<"$file")
    if [ -z "$tmp" ]; then
    #empty is ignored
    :;
    elif is_not_number "$tmp"; then
    echo "Error reading a number from $file" >&2
    echo "error: not a number, please give me a number!" > "$file"
    else
    # If it is ok, update the NUMCPUS value
    NUMCPUS=$tmp
    echo "ok $NUMCPUS" > "$file" # this will block until other side starts reading
    fi
    fi
    # last but not least, let's output it
    echo "$NUMCPUS"
    }

    # code duplication is the worst (ok, sometimes except for databases frameworks)
    get_num_bg_jobs() {
    jobs -p | wc -l
    }

    waitpid() {
    while
    (( $(get_num_bg_jobs) >= $(get_num_cpus) ))
    do
    wait -n
    done
    }

    # rest of the script

    NUMPCUS=10
    for(...) #Loop for each day
    do
    day=... #Set current day variable
    #Command to execute, put in background
    gLAB_linux -input "${day}folder/${day}.input" -output "${day)outfolder/${day}.output" &
    #Wait for any process to finish if NUMCPUS number of processes are running in background
    waitpid
    done


    And changing the value script could look like this:



    #!/bin/bash

    # shared context between scripts
    declare -r file="/tmp/signal_num_cpus"

    mkfifo "$file"

    echo 1 > "$file" # this will block until other side will start reading

    IFS= read -r line < "$file"

    case "$line" in
    ok*)
    read _ numcpus <<<"$line"
    echo "the script changed the number of numcpus to $numcpus"
    ;;
    *)
    echo "the script errored with $error"
    ;;
    esac

    rm "$file"


    Marks:




    • the correct way to define a function is func() { :; } Using function func { } is somthing taken from ksh and is supported as an extension. Use func() {}

    • It is nice to use arithmetic expansion (( ... )) for number comparisons nad handling.

    • Using backticks ` for command substitution $( ... ) is deprecated.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 22 '18 at 12:35









    Kamil CukKamil Cuk

    14.2k2533




    14.2k2533













    • Your method for using a file I find it way too complicated, specially regardind the use of "declare" and mkfifo. Maybe because I forgot to clarify some things in my questions (see edit in my question). I will edit (again) my question for adding my proposal

      – AwkMan
      Nov 22 '18 at 13:41











    • declare is just there to simplify reading, you can toss them all out. mkfifo is used because it's easier to synchronize processes using them, you can use normal file + flock or disregard locking altogether. If you search for multiple instances of the script to run, append unique name to the config-filename in each script, for example by using $$.

      – Kamil Cuk
      Nov 22 '18 at 13:49



















    • Your method for using a file I find it way too complicated, specially regardind the use of "declare" and mkfifo. Maybe because I forgot to clarify some things in my questions (see edit in my question). I will edit (again) my question for adding my proposal

      – AwkMan
      Nov 22 '18 at 13:41











    • declare is just there to simplify reading, you can toss them all out. mkfifo is used because it's easier to synchronize processes using them, you can use normal file + flock or disregard locking altogether. If you search for multiple instances of the script to run, append unique name to the config-filename in each script, for example by using $$.

      – Kamil Cuk
      Nov 22 '18 at 13:49

















    Your method for using a file I find it way too complicated, specially regardind the use of "declare" and mkfifo. Maybe because I forgot to clarify some things in my questions (see edit in my question). I will edit (again) my question for adding my proposal

    – AwkMan
    Nov 22 '18 at 13:41





    Your method for using a file I find it way too complicated, specially regardind the use of "declare" and mkfifo. Maybe because I forgot to clarify some things in my questions (see edit in my question). I will edit (again) my question for adding my proposal

    – AwkMan
    Nov 22 '18 at 13:41













    declare is just there to simplify reading, you can toss them all out. mkfifo is used because it's easier to synchronize processes using them, you can use normal file + flock or disregard locking altogether. If you search for multiple instances of the script to run, append unique name to the config-filename in each script, for example by using $$.

    – Kamil Cuk
    Nov 22 '18 at 13:49





    declare is just there to simplify reading, you can toss them all out. mkfifo is used because it's easier to synchronize processes using them, you can use normal file + flock or disregard locking altogether. If you search for multiple instances of the script to run, append unique name to the config-filename in each script, for example by using $$.

    – Kamil Cuk
    Nov 22 '18 at 13:49













    1














    Chapter 7.1 of GNU Parallel 2018 covers how to change the number of threads to use while running https://zenodo.org/record/1146014



    echo 50% > my_jobs
    /usr/bin/time parallel -N0 --jobs my_jobs sleep 1 :::: num128 &
    sleep 1
    echo 0 > my_jobs
    wait


    So you simply put the argument for --jobs into my_jobs and GNU Parallel will read this after each completed job.






    share|improve this answer




























      1














      Chapter 7.1 of GNU Parallel 2018 covers how to change the number of threads to use while running https://zenodo.org/record/1146014



      echo 50% > my_jobs
      /usr/bin/time parallel -N0 --jobs my_jobs sleep 1 :::: num128 &
      sleep 1
      echo 0 > my_jobs
      wait


      So you simply put the argument for --jobs into my_jobs and GNU Parallel will read this after each completed job.






      share|improve this answer


























        1












        1








        1







        Chapter 7.1 of GNU Parallel 2018 covers how to change the number of threads to use while running https://zenodo.org/record/1146014



        echo 50% > my_jobs
        /usr/bin/time parallel -N0 --jobs my_jobs sleep 1 :::: num128 &
        sleep 1
        echo 0 > my_jobs
        wait


        So you simply put the argument for --jobs into my_jobs and GNU Parallel will read this after each completed job.






        share|improve this answer













        Chapter 7.1 of GNU Parallel 2018 covers how to change the number of threads to use while running https://zenodo.org/record/1146014



        echo 50% > my_jobs
        /usr/bin/time parallel -N0 --jobs my_jobs sleep 1 :::: num128 &
        sleep 1
        echo 0 > my_jobs
        wait


        So you simply put the argument for --jobs into my_jobs and GNU Parallel will read this after each completed job.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 28 '18 at 19:55









        Ole TangeOle Tange

        20.1k35769




        20.1k35769






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53430218%2fmodify-a-variable-in-a-running-bash-script%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Guess what letter conforming each word

            Port of Spain

            Run scheduled task as local user group (not BUILTIN)