change environment of a running process

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












17















How might it be possible to alter some variable in the env of an already running process, for example through /proc/PID/environ? That "file" is read-only.



Need to change or unset the DISPLAY variable of a long-running batch job without killing it.










share|improve this question



















  • 3





    It's too late now, but for future reference, xpra could be interesting.

    – sr_
    May 9 '12 at 9:56











  • xpra sounds useful. Normally I reroute to non-user displays hosted by Xvfb or Xephyr, but today I forgot and ran from cli rather than cron/at to troubleshoot output, so it's been annoying me at :0

    – Marcos
    May 9 '12 at 11:12
















17















How might it be possible to alter some variable in the env of an already running process, for example through /proc/PID/environ? That "file" is read-only.



Need to change or unset the DISPLAY variable of a long-running batch job without killing it.










share|improve this question



















  • 3





    It's too late now, but for future reference, xpra could be interesting.

    – sr_
    May 9 '12 at 9:56











  • xpra sounds useful. Normally I reroute to non-user displays hosted by Xvfb or Xephyr, but today I forgot and ran from cli rather than cron/at to troubleshoot output, so it's been annoying me at :0

    – Marcos
    May 9 '12 at 11:12














17












17








17


4






How might it be possible to alter some variable in the env of an already running process, for example through /proc/PID/environ? That "file" is read-only.



Need to change or unset the DISPLAY variable of a long-running batch job without killing it.










share|improve this question
















How might it be possible to alter some variable in the env of an already running process, for example through /proc/PID/environ? That "file" is read-only.



Need to change or unset the DISPLAY variable of a long-running batch job without killing it.







environment-variables proc






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 9 '12 at 9:54









Sam

1,34031628




1,34031628










asked May 9 '12 at 9:02









MarcosMarcos

1,14211228




1,14211228







  • 3





    It's too late now, but for future reference, xpra could be interesting.

    – sr_
    May 9 '12 at 9:56











  • xpra sounds useful. Normally I reroute to non-user displays hosted by Xvfb or Xephyr, but today I forgot and ran from cli rather than cron/at to troubleshoot output, so it's been annoying me at :0

    – Marcos
    May 9 '12 at 11:12













  • 3





    It's too late now, but for future reference, xpra could be interesting.

    – sr_
    May 9 '12 at 9:56











  • xpra sounds useful. Normally I reroute to non-user displays hosted by Xvfb or Xephyr, but today I forgot and ran from cli rather than cron/at to troubleshoot output, so it's been annoying me at :0

    – Marcos
    May 9 '12 at 11:12








3




3





It's too late now, but for future reference, xpra could be interesting.

– sr_
May 9 '12 at 9:56





It's too late now, but for future reference, xpra could be interesting.

– sr_
May 9 '12 at 9:56













xpra sounds useful. Normally I reroute to non-user displays hosted by Xvfb or Xephyr, but today I forgot and ran from cli rather than cron/at to troubleshoot output, so it's been annoying me at :0

– Marcos
May 9 '12 at 11:12






xpra sounds useful. Normally I reroute to non-user displays hosted by Xvfb or Xephyr, but today I forgot and ran from cli rather than cron/at to troubleshoot output, so it's been annoying me at :0

– Marcos
May 9 '12 at 11:12











2 Answers
2






active

oldest

votes


















17














You can't do this without a nasty hacks - there's no API for this, no way to notify the process that its environment has changed (since that's not really possible anyway).

Even if you do manage to do that, there is no way to be sure that it will have any effect - the process could very well have cached the environment variable you're trying to poke (since nothing is supposed to be able to change it).



If you really do want to do this, and are prepared to pick up the pieces if things go wrong, you can use a debugger. See for instance this Stack Overflow question:
Is there a way to change another process's environment variables?



Essentially:



(gdb) attach process_id
(gdb) call putenv ("DISPLAY=your.new:value")
(gdb) detach


Other possible functions you could try to call are setenv or unsetenv.



Please do really keep in mind that this may not work, or have dire consequences if the process you target does "interesting" things with its environment block. Do test it out on non-critical processes first, but make sure these test processes mirror as close as possible the one you're trying to poke.






share|improve this answer




















  • 3





    Yes I realize it's somewhat of a hack, risky and not guaranteed for reasons you mentioned. (Part of the reason I visit this group is for such non-conventional needs I can't seem to find ordinarily.) In this case setting DISPLAY to junk or empty merely resolves an annoyance and delay(unnecessary frequent screenshots over network,fine if they fail). Since child copies parent, I need only mod the parent env. Many new child &subchild processes are getting spawned and exit quickly in my batch job; those matter. I figured a debugger could do this, thanks--I could wrap that into a shell function.

    – Marcos
    May 9 '12 at 11:02


















0














There is no need to do so if a batch job can read from a file system to retrieve a change. Just run a job with path to a temporary unique directory and pass the same path to the child shell script. Script will lock a file in that directory and write a file with new values near the lock file. A job script time to time will lock the same file, parse and read changes back from the values file. To find out how to make a lock in the unix shell just search for unix shell lock file or bash lock file, there is already exist a plenty solutions for that.



Benefits from this solution:



  • portable between almost any OS like Windows or Unix

  • no need to write and duplicate complex parsers for each interpreter (unix/windows/etc) to read back values from the file as long as the values file stays simple

Issues in implementation below:



  • Implementation relies on a file lock in a shell redirection phase (flock in Linux to achieve exclusion effect, in Windows has a builtin exclusion)

  • Each value for a variable is a single line value (not a multiline)

Implementation is stored here: https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Scripts/Tools



The bash implementation:



set_vars_from_locked_file_pair.sh



#!/bin/bash

# Another variant of a configuration file variables read and set script.
# The script must stay as simple as possible, so for this task it uses these parameters:
# 1. path where to lock a lock file
# 2. path where to read a file with variable names (each per line)
# 3. path where to read a file with variable values (each per line, must be the same quantity of lines with the variable names file)

# Script can be ONLY included by "source" command.
if [[ -n "$BASH" && (-z "$BASH_LINENO" || $BASH_LINENO[0] -gt 0) ]]; then

function set_vars_from_locked_file_pair()

# the lock file directory must already exist
if [[ ! -d "$1%[/\]*" ]]; then
echo "$0: error: lock file directory does not exist: `$1%[/\]*`" >&2
return 1
fi

if [[ ! -f "$2//\//" ]]; then
echo "$0: error: variable names file does not exist: `$2`" >&2
return 2
fi

if [[ ! -f "$3//\//" ]]; then
echo "$0: error: variable values file does not exist: `$3`" >&2
return 3
fi

function LocalMain()

# open file for direct reading by the `read` in the same shell process
exec 7< "$2"
exec 8< "$3"

# cleanup on return
trap "rm -f "$1" 2> /dev/null; exec 8>&-; exec 7>&-; trap - RETURN" RETURN

local __VarName
local __VarValue

# shared acquire of the lock file
while :; do
# lock via redirection to file

flock -s 9

# simultaneous iteration over 2 lists in the same time
while read -r -u 7 __VarName; do
read -r -u 8 __VarValue
# drop line returns
__VarName="$__VarName//[$'rn']"
__VarValue="$__VarValue//[$'rn']"
declare -gx $__VarName="$__VarValue"
(( $4 )) && echo "$__VarName=`$__VarValue`"
done

break

# return with previous code
9> "$1" 2> /dev/null # has exclusive lock been acquired?

# busy wait
sleep 0.02
done


LocalMain "$1//\//" "$2//\//" "$3//\//" "$4:-0"


fi


testlock.sh



#!/bin/bash


flock -x 9 2> /dev/null
read -n1 -r -p "Press any key to continue..."
echo >&2
9> "lock"


The same on Windows (as an example of portability):



set_vars_from_locked_file_pair.bat



@echo off

rem Another variant of a configuration file variables read and set script.
rem The script must stay as simple as possible, so for this task it uses these parameters:
rem 1. path where to lock a lock file
rem 2. path where to read a file with variable names (each per line)
rem 3. path where to read a file with variable values (each per line, must be the same quantity of lines with the variable names file)

rem disable alternative variables expansion to avoid `!` character consumption
setlocal DISABLEDELAYEDEXPANSION

set "FILE_LOCK_PATH=%~1"
set "FILE_VAR_NAMES_PATH=%~2"
set "FILE_VAR_VALUES_PATH=%~3"
set "PRINT_VARS_SET=%~4"

set "FILE_LOCK_DIR=%~d1"

rem the lock file directory must already exist
if not exist "%FILE_LOCK_DIR%" (
echo.%~nx0: error: FILE_LOCK_DIR does not exist: "%FILE_LOCK_DIR%"
exit /b 1
) >&2

if not exist "%FILE_VAR_NAMES_PATH%" (
echo.%~nx0: error: FILE_VAR_NAMES_PATH does not exist: "%FILE_VAR_NAMES_PATH%"
exit /b 2
) >&2

if not exist "%FILE_VAR_VALUES_PATH%" (
echo.%~nx0: error: FILE_VAR_VALUES_PATH does not exist: "%FILE_VAR_VALUES_PATH%"
exit /b 3
) >&2

rem The endlocal works only in the same call context
endlocal

rem exclusive acquire of the lock file
:REPEAT_LOCK_LOOP

(
(
rem if lock is acquired, then we are in...
call :MAIN "%%~2" "%%~3" "%%~4"
call set "LASTERROR=%%ERRORLEVEL%%"

rem exit with return code from the MAIN
) 9> "%~1" && (del /F /Q /A:-D "%~1" & goto EXIT)
) 2>nul

rem Busy wait: with external call significantly reduces CPU consumption while in a waiting state
pathping localhost -n -q 1 -p 20 >nul 2>&1
goto REPEAT_LOCK_LOOP

:EXIT
exit /b %LASTERROR%

:MAIN
rem drop last error
type nul>nul

if %~30 NEQ 0 goto SET_WITH_PRINT

rem trick with simultaneous iteration over 2 lists in the same time
(
for /f "usebackq eol=# tokens=* delims=" %%i in ("%~1") do (
set /p "%%i="
)
) < "%~2"

exit /b

:SET_WITH_PRINT
rem trick with simultaneous iteration over 2 lists in the same time
(
for /f "usebackq eol=# tokens=* delims=" %%i in ("%~1") do (
set /p "%%i="
rem to filter out wrong matches of a variable from the `set "%%i"`
for /f "usebackq eol=# tokens=1,* delims==" %%j in (`set "%%i"`) do if "%%j" == "%%i" echo.%%i=%%k
)
) < "%~2"


testlock.bat



@echo off

(
pause
) 9> ./lock


To write the files in just make the same way lock in your code.






share|improve this answer
























    Your Answer








    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "106"
    ;
    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: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    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%2funix.stackexchange.com%2fquestions%2f38205%2fchange-environment-of-a-running-process%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









    17














    You can't do this without a nasty hacks - there's no API for this, no way to notify the process that its environment has changed (since that's not really possible anyway).

    Even if you do manage to do that, there is no way to be sure that it will have any effect - the process could very well have cached the environment variable you're trying to poke (since nothing is supposed to be able to change it).



    If you really do want to do this, and are prepared to pick up the pieces if things go wrong, you can use a debugger. See for instance this Stack Overflow question:
    Is there a way to change another process's environment variables?



    Essentially:



    (gdb) attach process_id
    (gdb) call putenv ("DISPLAY=your.new:value")
    (gdb) detach


    Other possible functions you could try to call are setenv or unsetenv.



    Please do really keep in mind that this may not work, or have dire consequences if the process you target does "interesting" things with its environment block. Do test it out on non-critical processes first, but make sure these test processes mirror as close as possible the one you're trying to poke.






    share|improve this answer




















    • 3





      Yes I realize it's somewhat of a hack, risky and not guaranteed for reasons you mentioned. (Part of the reason I visit this group is for such non-conventional needs I can't seem to find ordinarily.) In this case setting DISPLAY to junk or empty merely resolves an annoyance and delay(unnecessary frequent screenshots over network,fine if they fail). Since child copies parent, I need only mod the parent env. Many new child &subchild processes are getting spawned and exit quickly in my batch job; those matter. I figured a debugger could do this, thanks--I could wrap that into a shell function.

      – Marcos
      May 9 '12 at 11:02















    17














    You can't do this without a nasty hacks - there's no API for this, no way to notify the process that its environment has changed (since that's not really possible anyway).

    Even if you do manage to do that, there is no way to be sure that it will have any effect - the process could very well have cached the environment variable you're trying to poke (since nothing is supposed to be able to change it).



    If you really do want to do this, and are prepared to pick up the pieces if things go wrong, you can use a debugger. See for instance this Stack Overflow question:
    Is there a way to change another process's environment variables?



    Essentially:



    (gdb) attach process_id
    (gdb) call putenv ("DISPLAY=your.new:value")
    (gdb) detach


    Other possible functions you could try to call are setenv or unsetenv.



    Please do really keep in mind that this may not work, or have dire consequences if the process you target does "interesting" things with its environment block. Do test it out on non-critical processes first, but make sure these test processes mirror as close as possible the one you're trying to poke.






    share|improve this answer




















    • 3





      Yes I realize it's somewhat of a hack, risky and not guaranteed for reasons you mentioned. (Part of the reason I visit this group is for such non-conventional needs I can't seem to find ordinarily.) In this case setting DISPLAY to junk or empty merely resolves an annoyance and delay(unnecessary frequent screenshots over network,fine if they fail). Since child copies parent, I need only mod the parent env. Many new child &subchild processes are getting spawned and exit quickly in my batch job; those matter. I figured a debugger could do this, thanks--I could wrap that into a shell function.

      – Marcos
      May 9 '12 at 11:02













    17












    17








    17







    You can't do this without a nasty hacks - there's no API for this, no way to notify the process that its environment has changed (since that's not really possible anyway).

    Even if you do manage to do that, there is no way to be sure that it will have any effect - the process could very well have cached the environment variable you're trying to poke (since nothing is supposed to be able to change it).



    If you really do want to do this, and are prepared to pick up the pieces if things go wrong, you can use a debugger. See for instance this Stack Overflow question:
    Is there a way to change another process's environment variables?



    Essentially:



    (gdb) attach process_id
    (gdb) call putenv ("DISPLAY=your.new:value")
    (gdb) detach


    Other possible functions you could try to call are setenv or unsetenv.



    Please do really keep in mind that this may not work, or have dire consequences if the process you target does "interesting" things with its environment block. Do test it out on non-critical processes first, but make sure these test processes mirror as close as possible the one you're trying to poke.






    share|improve this answer















    You can't do this without a nasty hacks - there's no API for this, no way to notify the process that its environment has changed (since that's not really possible anyway).

    Even if you do manage to do that, there is no way to be sure that it will have any effect - the process could very well have cached the environment variable you're trying to poke (since nothing is supposed to be able to change it).



    If you really do want to do this, and are prepared to pick up the pieces if things go wrong, you can use a debugger. See for instance this Stack Overflow question:
    Is there a way to change another process's environment variables?



    Essentially:



    (gdb) attach process_id
    (gdb) call putenv ("DISPLAY=your.new:value")
    (gdb) detach


    Other possible functions you could try to call are setenv or unsetenv.



    Please do really keep in mind that this may not work, or have dire consequences if the process you target does "interesting" things with its environment block. Do test it out on non-critical processes first, but make sure these test processes mirror as close as possible the one you're trying to poke.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited May 23 '17 at 12:40









    Community

    1




    1










    answered May 9 '12 at 10:30









    MatMat

    39.8k8123128




    39.8k8123128







    • 3





      Yes I realize it's somewhat of a hack, risky and not guaranteed for reasons you mentioned. (Part of the reason I visit this group is for such non-conventional needs I can't seem to find ordinarily.) In this case setting DISPLAY to junk or empty merely resolves an annoyance and delay(unnecessary frequent screenshots over network,fine if they fail). Since child copies parent, I need only mod the parent env. Many new child &subchild processes are getting spawned and exit quickly in my batch job; those matter. I figured a debugger could do this, thanks--I could wrap that into a shell function.

      – Marcos
      May 9 '12 at 11:02












    • 3





      Yes I realize it's somewhat of a hack, risky and not guaranteed for reasons you mentioned. (Part of the reason I visit this group is for such non-conventional needs I can't seem to find ordinarily.) In this case setting DISPLAY to junk or empty merely resolves an annoyance and delay(unnecessary frequent screenshots over network,fine if they fail). Since child copies parent, I need only mod the parent env. Many new child &subchild processes are getting spawned and exit quickly in my batch job; those matter. I figured a debugger could do this, thanks--I could wrap that into a shell function.

      – Marcos
      May 9 '12 at 11:02







    3




    3





    Yes I realize it's somewhat of a hack, risky and not guaranteed for reasons you mentioned. (Part of the reason I visit this group is for such non-conventional needs I can't seem to find ordinarily.) In this case setting DISPLAY to junk or empty merely resolves an annoyance and delay(unnecessary frequent screenshots over network,fine if they fail). Since child copies parent, I need only mod the parent env. Many new child &subchild processes are getting spawned and exit quickly in my batch job; those matter. I figured a debugger could do this, thanks--I could wrap that into a shell function.

    – Marcos
    May 9 '12 at 11:02





    Yes I realize it's somewhat of a hack, risky and not guaranteed for reasons you mentioned. (Part of the reason I visit this group is for such non-conventional needs I can't seem to find ordinarily.) In this case setting DISPLAY to junk or empty merely resolves an annoyance and delay(unnecessary frequent screenshots over network,fine if they fail). Since child copies parent, I need only mod the parent env. Many new child &subchild processes are getting spawned and exit quickly in my batch job; those matter. I figured a debugger could do this, thanks--I could wrap that into a shell function.

    – Marcos
    May 9 '12 at 11:02













    0














    There is no need to do so if a batch job can read from a file system to retrieve a change. Just run a job with path to a temporary unique directory and pass the same path to the child shell script. Script will lock a file in that directory and write a file with new values near the lock file. A job script time to time will lock the same file, parse and read changes back from the values file. To find out how to make a lock in the unix shell just search for unix shell lock file or bash lock file, there is already exist a plenty solutions for that.



    Benefits from this solution:



    • portable between almost any OS like Windows or Unix

    • no need to write and duplicate complex parsers for each interpreter (unix/windows/etc) to read back values from the file as long as the values file stays simple

    Issues in implementation below:



    • Implementation relies on a file lock in a shell redirection phase (flock in Linux to achieve exclusion effect, in Windows has a builtin exclusion)

    • Each value for a variable is a single line value (not a multiline)

    Implementation is stored here: https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Scripts/Tools



    The bash implementation:



    set_vars_from_locked_file_pair.sh



    #!/bin/bash

    # Another variant of a configuration file variables read and set script.
    # The script must stay as simple as possible, so for this task it uses these parameters:
    # 1. path where to lock a lock file
    # 2. path where to read a file with variable names (each per line)
    # 3. path where to read a file with variable values (each per line, must be the same quantity of lines with the variable names file)

    # Script can be ONLY included by "source" command.
    if [[ -n "$BASH" && (-z "$BASH_LINENO" || $BASH_LINENO[0] -gt 0) ]]; then

    function set_vars_from_locked_file_pair()

    # the lock file directory must already exist
    if [[ ! -d "$1%[/\]*" ]]; then
    echo "$0: error: lock file directory does not exist: `$1%[/\]*`" >&2
    return 1
    fi

    if [[ ! -f "$2//\//" ]]; then
    echo "$0: error: variable names file does not exist: `$2`" >&2
    return 2
    fi

    if [[ ! -f "$3//\//" ]]; then
    echo "$0: error: variable values file does not exist: `$3`" >&2
    return 3
    fi

    function LocalMain()

    # open file for direct reading by the `read` in the same shell process
    exec 7< "$2"
    exec 8< "$3"

    # cleanup on return
    trap "rm -f "$1" 2> /dev/null; exec 8>&-; exec 7>&-; trap - RETURN" RETURN

    local __VarName
    local __VarValue

    # shared acquire of the lock file
    while :; do
    # lock via redirection to file

    flock -s 9

    # simultaneous iteration over 2 lists in the same time
    while read -r -u 7 __VarName; do
    read -r -u 8 __VarValue
    # drop line returns
    __VarName="$__VarName//[$'rn']"
    __VarValue="$__VarValue//[$'rn']"
    declare -gx $__VarName="$__VarValue"
    (( $4 )) && echo "$__VarName=`$__VarValue`"
    done

    break

    # return with previous code
    9> "$1" 2> /dev/null # has exclusive lock been acquired?

    # busy wait
    sleep 0.02
    done


    LocalMain "$1//\//" "$2//\//" "$3//\//" "$4:-0"


    fi


    testlock.sh



    #!/bin/bash


    flock -x 9 2> /dev/null
    read -n1 -r -p "Press any key to continue..."
    echo >&2
    9> "lock"


    The same on Windows (as an example of portability):



    set_vars_from_locked_file_pair.bat



    @echo off

    rem Another variant of a configuration file variables read and set script.
    rem The script must stay as simple as possible, so for this task it uses these parameters:
    rem 1. path where to lock a lock file
    rem 2. path where to read a file with variable names (each per line)
    rem 3. path where to read a file with variable values (each per line, must be the same quantity of lines with the variable names file)

    rem disable alternative variables expansion to avoid `!` character consumption
    setlocal DISABLEDELAYEDEXPANSION

    set "FILE_LOCK_PATH=%~1"
    set "FILE_VAR_NAMES_PATH=%~2"
    set "FILE_VAR_VALUES_PATH=%~3"
    set "PRINT_VARS_SET=%~4"

    set "FILE_LOCK_DIR=%~d1"

    rem the lock file directory must already exist
    if not exist "%FILE_LOCK_DIR%" (
    echo.%~nx0: error: FILE_LOCK_DIR does not exist: "%FILE_LOCK_DIR%"
    exit /b 1
    ) >&2

    if not exist "%FILE_VAR_NAMES_PATH%" (
    echo.%~nx0: error: FILE_VAR_NAMES_PATH does not exist: "%FILE_VAR_NAMES_PATH%"
    exit /b 2
    ) >&2

    if not exist "%FILE_VAR_VALUES_PATH%" (
    echo.%~nx0: error: FILE_VAR_VALUES_PATH does not exist: "%FILE_VAR_VALUES_PATH%"
    exit /b 3
    ) >&2

    rem The endlocal works only in the same call context
    endlocal

    rem exclusive acquire of the lock file
    :REPEAT_LOCK_LOOP

    (
    (
    rem if lock is acquired, then we are in...
    call :MAIN "%%~2" "%%~3" "%%~4"
    call set "LASTERROR=%%ERRORLEVEL%%"

    rem exit with return code from the MAIN
    ) 9> "%~1" && (del /F /Q /A:-D "%~1" & goto EXIT)
    ) 2>nul

    rem Busy wait: with external call significantly reduces CPU consumption while in a waiting state
    pathping localhost -n -q 1 -p 20 >nul 2>&1
    goto REPEAT_LOCK_LOOP

    :EXIT
    exit /b %LASTERROR%

    :MAIN
    rem drop last error
    type nul>nul

    if %~30 NEQ 0 goto SET_WITH_PRINT

    rem trick with simultaneous iteration over 2 lists in the same time
    (
    for /f "usebackq eol=# tokens=* delims=" %%i in ("%~1") do (
    set /p "%%i="
    )
    ) < "%~2"

    exit /b

    :SET_WITH_PRINT
    rem trick with simultaneous iteration over 2 lists in the same time
    (
    for /f "usebackq eol=# tokens=* delims=" %%i in ("%~1") do (
    set /p "%%i="
    rem to filter out wrong matches of a variable from the `set "%%i"`
    for /f "usebackq eol=# tokens=1,* delims==" %%j in (`set "%%i"`) do if "%%j" == "%%i" echo.%%i=%%k
    )
    ) < "%~2"


    testlock.bat



    @echo off

    (
    pause
    ) 9> ./lock


    To write the files in just make the same way lock in your code.






    share|improve this answer





























      0














      There is no need to do so if a batch job can read from a file system to retrieve a change. Just run a job with path to a temporary unique directory and pass the same path to the child shell script. Script will lock a file in that directory and write a file with new values near the lock file. A job script time to time will lock the same file, parse and read changes back from the values file. To find out how to make a lock in the unix shell just search for unix shell lock file or bash lock file, there is already exist a plenty solutions for that.



      Benefits from this solution:



      • portable between almost any OS like Windows or Unix

      • no need to write and duplicate complex parsers for each interpreter (unix/windows/etc) to read back values from the file as long as the values file stays simple

      Issues in implementation below:



      • Implementation relies on a file lock in a shell redirection phase (flock in Linux to achieve exclusion effect, in Windows has a builtin exclusion)

      • Each value for a variable is a single line value (not a multiline)

      Implementation is stored here: https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Scripts/Tools



      The bash implementation:



      set_vars_from_locked_file_pair.sh



      #!/bin/bash

      # Another variant of a configuration file variables read and set script.
      # The script must stay as simple as possible, so for this task it uses these parameters:
      # 1. path where to lock a lock file
      # 2. path where to read a file with variable names (each per line)
      # 3. path where to read a file with variable values (each per line, must be the same quantity of lines with the variable names file)

      # Script can be ONLY included by "source" command.
      if [[ -n "$BASH" && (-z "$BASH_LINENO" || $BASH_LINENO[0] -gt 0) ]]; then

      function set_vars_from_locked_file_pair()

      # the lock file directory must already exist
      if [[ ! -d "$1%[/\]*" ]]; then
      echo "$0: error: lock file directory does not exist: `$1%[/\]*`" >&2
      return 1
      fi

      if [[ ! -f "$2//\//" ]]; then
      echo "$0: error: variable names file does not exist: `$2`" >&2
      return 2
      fi

      if [[ ! -f "$3//\//" ]]; then
      echo "$0: error: variable values file does not exist: `$3`" >&2
      return 3
      fi

      function LocalMain()

      # open file for direct reading by the `read` in the same shell process
      exec 7< "$2"
      exec 8< "$3"

      # cleanup on return
      trap "rm -f "$1" 2> /dev/null; exec 8>&-; exec 7>&-; trap - RETURN" RETURN

      local __VarName
      local __VarValue

      # shared acquire of the lock file
      while :; do
      # lock via redirection to file

      flock -s 9

      # simultaneous iteration over 2 lists in the same time
      while read -r -u 7 __VarName; do
      read -r -u 8 __VarValue
      # drop line returns
      __VarName="$__VarName//[$'rn']"
      __VarValue="$__VarValue//[$'rn']"
      declare -gx $__VarName="$__VarValue"
      (( $4 )) && echo "$__VarName=`$__VarValue`"
      done

      break

      # return with previous code
      9> "$1" 2> /dev/null # has exclusive lock been acquired?

      # busy wait
      sleep 0.02
      done


      LocalMain "$1//\//" "$2//\//" "$3//\//" "$4:-0"


      fi


      testlock.sh



      #!/bin/bash


      flock -x 9 2> /dev/null
      read -n1 -r -p "Press any key to continue..."
      echo >&2
      9> "lock"


      The same on Windows (as an example of portability):



      set_vars_from_locked_file_pair.bat



      @echo off

      rem Another variant of a configuration file variables read and set script.
      rem The script must stay as simple as possible, so for this task it uses these parameters:
      rem 1. path where to lock a lock file
      rem 2. path where to read a file with variable names (each per line)
      rem 3. path where to read a file with variable values (each per line, must be the same quantity of lines with the variable names file)

      rem disable alternative variables expansion to avoid `!` character consumption
      setlocal DISABLEDELAYEDEXPANSION

      set "FILE_LOCK_PATH=%~1"
      set "FILE_VAR_NAMES_PATH=%~2"
      set "FILE_VAR_VALUES_PATH=%~3"
      set "PRINT_VARS_SET=%~4"

      set "FILE_LOCK_DIR=%~d1"

      rem the lock file directory must already exist
      if not exist "%FILE_LOCK_DIR%" (
      echo.%~nx0: error: FILE_LOCK_DIR does not exist: "%FILE_LOCK_DIR%"
      exit /b 1
      ) >&2

      if not exist "%FILE_VAR_NAMES_PATH%" (
      echo.%~nx0: error: FILE_VAR_NAMES_PATH does not exist: "%FILE_VAR_NAMES_PATH%"
      exit /b 2
      ) >&2

      if not exist "%FILE_VAR_VALUES_PATH%" (
      echo.%~nx0: error: FILE_VAR_VALUES_PATH does not exist: "%FILE_VAR_VALUES_PATH%"
      exit /b 3
      ) >&2

      rem The endlocal works only in the same call context
      endlocal

      rem exclusive acquire of the lock file
      :REPEAT_LOCK_LOOP

      (
      (
      rem if lock is acquired, then we are in...
      call :MAIN "%%~2" "%%~3" "%%~4"
      call set "LASTERROR=%%ERRORLEVEL%%"

      rem exit with return code from the MAIN
      ) 9> "%~1" && (del /F /Q /A:-D "%~1" & goto EXIT)
      ) 2>nul

      rem Busy wait: with external call significantly reduces CPU consumption while in a waiting state
      pathping localhost -n -q 1 -p 20 >nul 2>&1
      goto REPEAT_LOCK_LOOP

      :EXIT
      exit /b %LASTERROR%

      :MAIN
      rem drop last error
      type nul>nul

      if %~30 NEQ 0 goto SET_WITH_PRINT

      rem trick with simultaneous iteration over 2 lists in the same time
      (
      for /f "usebackq eol=# tokens=* delims=" %%i in ("%~1") do (
      set /p "%%i="
      )
      ) < "%~2"

      exit /b

      :SET_WITH_PRINT
      rem trick with simultaneous iteration over 2 lists in the same time
      (
      for /f "usebackq eol=# tokens=* delims=" %%i in ("%~1") do (
      set /p "%%i="
      rem to filter out wrong matches of a variable from the `set "%%i"`
      for /f "usebackq eol=# tokens=1,* delims==" %%j in (`set "%%i"`) do if "%%j" == "%%i" echo.%%i=%%k
      )
      ) < "%~2"


      testlock.bat



      @echo off

      (
      pause
      ) 9> ./lock


      To write the files in just make the same way lock in your code.






      share|improve this answer



























        0












        0








        0







        There is no need to do so if a batch job can read from a file system to retrieve a change. Just run a job with path to a temporary unique directory and pass the same path to the child shell script. Script will lock a file in that directory and write a file with new values near the lock file. A job script time to time will lock the same file, parse and read changes back from the values file. To find out how to make a lock in the unix shell just search for unix shell lock file or bash lock file, there is already exist a plenty solutions for that.



        Benefits from this solution:



        • portable between almost any OS like Windows or Unix

        • no need to write and duplicate complex parsers for each interpreter (unix/windows/etc) to read back values from the file as long as the values file stays simple

        Issues in implementation below:



        • Implementation relies on a file lock in a shell redirection phase (flock in Linux to achieve exclusion effect, in Windows has a builtin exclusion)

        • Each value for a variable is a single line value (not a multiline)

        Implementation is stored here: https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Scripts/Tools



        The bash implementation:



        set_vars_from_locked_file_pair.sh



        #!/bin/bash

        # Another variant of a configuration file variables read and set script.
        # The script must stay as simple as possible, so for this task it uses these parameters:
        # 1. path where to lock a lock file
        # 2. path where to read a file with variable names (each per line)
        # 3. path where to read a file with variable values (each per line, must be the same quantity of lines with the variable names file)

        # Script can be ONLY included by "source" command.
        if [[ -n "$BASH" && (-z "$BASH_LINENO" || $BASH_LINENO[0] -gt 0) ]]; then

        function set_vars_from_locked_file_pair()

        # the lock file directory must already exist
        if [[ ! -d "$1%[/\]*" ]]; then
        echo "$0: error: lock file directory does not exist: `$1%[/\]*`" >&2
        return 1
        fi

        if [[ ! -f "$2//\//" ]]; then
        echo "$0: error: variable names file does not exist: `$2`" >&2
        return 2
        fi

        if [[ ! -f "$3//\//" ]]; then
        echo "$0: error: variable values file does not exist: `$3`" >&2
        return 3
        fi

        function LocalMain()

        # open file for direct reading by the `read` in the same shell process
        exec 7< "$2"
        exec 8< "$3"

        # cleanup on return
        trap "rm -f "$1" 2> /dev/null; exec 8>&-; exec 7>&-; trap - RETURN" RETURN

        local __VarName
        local __VarValue

        # shared acquire of the lock file
        while :; do
        # lock via redirection to file

        flock -s 9

        # simultaneous iteration over 2 lists in the same time
        while read -r -u 7 __VarName; do
        read -r -u 8 __VarValue
        # drop line returns
        __VarName="$__VarName//[$'rn']"
        __VarValue="$__VarValue//[$'rn']"
        declare -gx $__VarName="$__VarValue"
        (( $4 )) && echo "$__VarName=`$__VarValue`"
        done

        break

        # return with previous code
        9> "$1" 2> /dev/null # has exclusive lock been acquired?

        # busy wait
        sleep 0.02
        done


        LocalMain "$1//\//" "$2//\//" "$3//\//" "$4:-0"


        fi


        testlock.sh



        #!/bin/bash


        flock -x 9 2> /dev/null
        read -n1 -r -p "Press any key to continue..."
        echo >&2
        9> "lock"


        The same on Windows (as an example of portability):



        set_vars_from_locked_file_pair.bat



        @echo off

        rem Another variant of a configuration file variables read and set script.
        rem The script must stay as simple as possible, so for this task it uses these parameters:
        rem 1. path where to lock a lock file
        rem 2. path where to read a file with variable names (each per line)
        rem 3. path where to read a file with variable values (each per line, must be the same quantity of lines with the variable names file)

        rem disable alternative variables expansion to avoid `!` character consumption
        setlocal DISABLEDELAYEDEXPANSION

        set "FILE_LOCK_PATH=%~1"
        set "FILE_VAR_NAMES_PATH=%~2"
        set "FILE_VAR_VALUES_PATH=%~3"
        set "PRINT_VARS_SET=%~4"

        set "FILE_LOCK_DIR=%~d1"

        rem the lock file directory must already exist
        if not exist "%FILE_LOCK_DIR%" (
        echo.%~nx0: error: FILE_LOCK_DIR does not exist: "%FILE_LOCK_DIR%"
        exit /b 1
        ) >&2

        if not exist "%FILE_VAR_NAMES_PATH%" (
        echo.%~nx0: error: FILE_VAR_NAMES_PATH does not exist: "%FILE_VAR_NAMES_PATH%"
        exit /b 2
        ) >&2

        if not exist "%FILE_VAR_VALUES_PATH%" (
        echo.%~nx0: error: FILE_VAR_VALUES_PATH does not exist: "%FILE_VAR_VALUES_PATH%"
        exit /b 3
        ) >&2

        rem The endlocal works only in the same call context
        endlocal

        rem exclusive acquire of the lock file
        :REPEAT_LOCK_LOOP

        (
        (
        rem if lock is acquired, then we are in...
        call :MAIN "%%~2" "%%~3" "%%~4"
        call set "LASTERROR=%%ERRORLEVEL%%"

        rem exit with return code from the MAIN
        ) 9> "%~1" && (del /F /Q /A:-D "%~1" & goto EXIT)
        ) 2>nul

        rem Busy wait: with external call significantly reduces CPU consumption while in a waiting state
        pathping localhost -n -q 1 -p 20 >nul 2>&1
        goto REPEAT_LOCK_LOOP

        :EXIT
        exit /b %LASTERROR%

        :MAIN
        rem drop last error
        type nul>nul

        if %~30 NEQ 0 goto SET_WITH_PRINT

        rem trick with simultaneous iteration over 2 lists in the same time
        (
        for /f "usebackq eol=# tokens=* delims=" %%i in ("%~1") do (
        set /p "%%i="
        )
        ) < "%~2"

        exit /b

        :SET_WITH_PRINT
        rem trick with simultaneous iteration over 2 lists in the same time
        (
        for /f "usebackq eol=# tokens=* delims=" %%i in ("%~1") do (
        set /p "%%i="
        rem to filter out wrong matches of a variable from the `set "%%i"`
        for /f "usebackq eol=# tokens=1,* delims==" %%j in (`set "%%i"`) do if "%%j" == "%%i" echo.%%i=%%k
        )
        ) < "%~2"


        testlock.bat



        @echo off

        (
        pause
        ) 9> ./lock


        To write the files in just make the same way lock in your code.






        share|improve this answer















        There is no need to do so if a batch job can read from a file system to retrieve a change. Just run a job with path to a temporary unique directory and pass the same path to the child shell script. Script will lock a file in that directory and write a file with new values near the lock file. A job script time to time will lock the same file, parse and read changes back from the values file. To find out how to make a lock in the unix shell just search for unix shell lock file or bash lock file, there is already exist a plenty solutions for that.



        Benefits from this solution:



        • portable between almost any OS like Windows or Unix

        • no need to write and duplicate complex parsers for each interpreter (unix/windows/etc) to read back values from the file as long as the values file stays simple

        Issues in implementation below:



        • Implementation relies on a file lock in a shell redirection phase (flock in Linux to achieve exclusion effect, in Windows has a builtin exclusion)

        • Each value for a variable is a single line value (not a multiline)

        Implementation is stored here: https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Scripts/Tools



        The bash implementation:



        set_vars_from_locked_file_pair.sh



        #!/bin/bash

        # Another variant of a configuration file variables read and set script.
        # The script must stay as simple as possible, so for this task it uses these parameters:
        # 1. path where to lock a lock file
        # 2. path where to read a file with variable names (each per line)
        # 3. path where to read a file with variable values (each per line, must be the same quantity of lines with the variable names file)

        # Script can be ONLY included by "source" command.
        if [[ -n "$BASH" && (-z "$BASH_LINENO" || $BASH_LINENO[0] -gt 0) ]]; then

        function set_vars_from_locked_file_pair()

        # the lock file directory must already exist
        if [[ ! -d "$1%[/\]*" ]]; then
        echo "$0: error: lock file directory does not exist: `$1%[/\]*`" >&2
        return 1
        fi

        if [[ ! -f "$2//\//" ]]; then
        echo "$0: error: variable names file does not exist: `$2`" >&2
        return 2
        fi

        if [[ ! -f "$3//\//" ]]; then
        echo "$0: error: variable values file does not exist: `$3`" >&2
        return 3
        fi

        function LocalMain()

        # open file for direct reading by the `read` in the same shell process
        exec 7< "$2"
        exec 8< "$3"

        # cleanup on return
        trap "rm -f "$1" 2> /dev/null; exec 8>&-; exec 7>&-; trap - RETURN" RETURN

        local __VarName
        local __VarValue

        # shared acquire of the lock file
        while :; do
        # lock via redirection to file

        flock -s 9

        # simultaneous iteration over 2 lists in the same time
        while read -r -u 7 __VarName; do
        read -r -u 8 __VarValue
        # drop line returns
        __VarName="$__VarName//[$'rn']"
        __VarValue="$__VarValue//[$'rn']"
        declare -gx $__VarName="$__VarValue"
        (( $4 )) && echo "$__VarName=`$__VarValue`"
        done

        break

        # return with previous code
        9> "$1" 2> /dev/null # has exclusive lock been acquired?

        # busy wait
        sleep 0.02
        done


        LocalMain "$1//\//" "$2//\//" "$3//\//" "$4:-0"


        fi


        testlock.sh



        #!/bin/bash


        flock -x 9 2> /dev/null
        read -n1 -r -p "Press any key to continue..."
        echo >&2
        9> "lock"


        The same on Windows (as an example of portability):



        set_vars_from_locked_file_pair.bat



        @echo off

        rem Another variant of a configuration file variables read and set script.
        rem The script must stay as simple as possible, so for this task it uses these parameters:
        rem 1. path where to lock a lock file
        rem 2. path where to read a file with variable names (each per line)
        rem 3. path where to read a file with variable values (each per line, must be the same quantity of lines with the variable names file)

        rem disable alternative variables expansion to avoid `!` character consumption
        setlocal DISABLEDELAYEDEXPANSION

        set "FILE_LOCK_PATH=%~1"
        set "FILE_VAR_NAMES_PATH=%~2"
        set "FILE_VAR_VALUES_PATH=%~3"
        set "PRINT_VARS_SET=%~4"

        set "FILE_LOCK_DIR=%~d1"

        rem the lock file directory must already exist
        if not exist "%FILE_LOCK_DIR%" (
        echo.%~nx0: error: FILE_LOCK_DIR does not exist: "%FILE_LOCK_DIR%"
        exit /b 1
        ) >&2

        if not exist "%FILE_VAR_NAMES_PATH%" (
        echo.%~nx0: error: FILE_VAR_NAMES_PATH does not exist: "%FILE_VAR_NAMES_PATH%"
        exit /b 2
        ) >&2

        if not exist "%FILE_VAR_VALUES_PATH%" (
        echo.%~nx0: error: FILE_VAR_VALUES_PATH does not exist: "%FILE_VAR_VALUES_PATH%"
        exit /b 3
        ) >&2

        rem The endlocal works only in the same call context
        endlocal

        rem exclusive acquire of the lock file
        :REPEAT_LOCK_LOOP

        (
        (
        rem if lock is acquired, then we are in...
        call :MAIN "%%~2" "%%~3" "%%~4"
        call set "LASTERROR=%%ERRORLEVEL%%"

        rem exit with return code from the MAIN
        ) 9> "%~1" && (del /F /Q /A:-D "%~1" & goto EXIT)
        ) 2>nul

        rem Busy wait: with external call significantly reduces CPU consumption while in a waiting state
        pathping localhost -n -q 1 -p 20 >nul 2>&1
        goto REPEAT_LOCK_LOOP

        :EXIT
        exit /b %LASTERROR%

        :MAIN
        rem drop last error
        type nul>nul

        if %~30 NEQ 0 goto SET_WITH_PRINT

        rem trick with simultaneous iteration over 2 lists in the same time
        (
        for /f "usebackq eol=# tokens=* delims=" %%i in ("%~1") do (
        set /p "%%i="
        )
        ) < "%~2"

        exit /b

        :SET_WITH_PRINT
        rem trick with simultaneous iteration over 2 lists in the same time
        (
        for /f "usebackq eol=# tokens=* delims=" %%i in ("%~1") do (
        set /p "%%i="
        rem to filter out wrong matches of a variable from the `set "%%i"`
        for /f "usebackq eol=# tokens=1,* delims==" %%j in (`set "%%i"`) do if "%%j" == "%%i" echo.%%i=%%k
        )
        ) < "%~2"


        testlock.bat



        @echo off

        (
        pause
        ) 9> ./lock


        To write the files in just make the same way lock in your code.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Feb 26 at 2:04

























        answered Feb 21 at 17:05









        AndryAndry

        1012




        1012



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Unix & Linux Stack Exchange!


            • 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%2funix.stackexchange.com%2fquestions%2f38205%2fchange-environment-of-a-running-process%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

            How to check contact read email or not when send email to Individual?

            Displaying single band from multi-band raster using QGIS

            How many registers does an x86_64 CPU actually have?