змінити середовище запущеного процесу


18

Як можливо змінити якусь змінну у envвже запущеному процесі, наприклад, через /proc/PID/environ?"файл" read-only.

Потрібно змінити або зняти змінну DISPLAY тривалого пакетного завдання, не вбиваючи його.


3
Зараз уже пізно, але для подальшого ознайомлення це xpraможе бути цікаво.
sr_

xpraзвучить корисно. Зазвичай я перенаправляюсь на некористувацькі дисплеї, розміщені Xvfbабо Xephyr, але сьогодні я забув і перебіг з cli, а не cron / at, щоб усунути неполадки, тому це мене дратує в:0
Маркос,

Відповіді:


19

Ви не можете зробити це без неприємних злому - для цього немає API, жодного способу сповістити процес, що його середовище змінилося (оскільки це все-таки не можливо).
Навіть якщо вам це вдасться зробити, немає жодного способу бути впевненим, що це матиме якийсь ефект - процес міг би добре кешувати змінну середовища, про яку ви намагаєтеся тикнути (оскільки нічого, як передбачається, не зможе змінити ).

Якщо ви дійсно хочете це зробити, і готові забрати шматки, якщо все піде не так, ви можете скористатися налагоджувачем. Дивіться, наприклад, це запитання щодо переповнення стека:
Чи є спосіб зміни змінних оточення іншого процесу?

По суті:

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

Інші можливі функції, до яких можна спробувати зателефонувати, є setenvабо unsetenv.

Не забудьте пам’ятати, що це може не спрацьовувати або матиме жахливі наслідки, якщо процес, на який ви орієнтуєтесь, робить «цікаві» речі з його оточуючим блоком. Спершу протестуйте його на некритичних процесах, але переконайтесь, що ці тестові процеси відображаються якнайближче до тих, про які ви намагаєтеся натиснути.


3
Так, я усвідомлюю, що це здебільшого хакер, ризиковано і не гарантовано із зазначених вами причин. (Частина причини, що я відвідую цю групу, полягає в таких нетрадиційних потребах, які я, здається, не знаходжу звичайно.) У цьому випадку налаштування DISPLAY на сміття чи спорожнення просто вирішує роздратування та затримку (непотрібні часті знімки екрана через мережу, добре, якщо вони провалюються). Оскільки дитина копіює батьків, мені потрібен лише модуль батьківського оточення. Багато нових процесів, пов’язаних з дитиною та підростками, породжуються та швидко виходять з моєї пакетної роботи; ця матерія. Я подумав, що налагоджувач може це зробити, дякую - я міг би перетворити це на функцію оболонки.
Маркос

0

Цього не потрібно робити, якщо пакетне завдання може читати з файлової системи для отримання змін. Просто запустіть завдання зі шляху до тимчасового унікального каталогу та передайте той самий шлях до сценарію дочірньої оболонки. Сценарій заблокує файл у цій директорії та напише файл із новими значеннями поруч із файлом блокування. Час від часу сценарій завдання блокує той самий файл, розбирає та читає зміни з файлу значень. Щоб дізнатися, як зробити замок у оболонці unix, просто шукайте unix shell lock fileабо bash lock file, для цього вже існує маса рішень.

Переваги цього рішення:

  • портативний між майже будь-якою ОС, як Windows або Unix
  • не потрібно писати та копіювати складні парсери для кожного інтерпретатора (unix / windows / тощо), щоб читати назад значення з файлу, доки файл значень залишається простим

Питання щодо впровадження нижче:

  • Реалізація покладається на блокування файлів у фазі перенаправлення оболонки ( flockу Linux для досягнення ефекту виключення, у Windows є вбудований виключення)
  • Кожне значення змінної - це значення одного рядка (а не багаторядкового)

Реалізація зберігається тут: https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Scripts/Tools

bashРеалізація:

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//[$'\r\n']}"
          __VarValue="${__VarValue//[$'\r\n']}"
          # instead of `declare -gx` because `-g` is introduced only in `bash-4.2-alpha`
          export $__VarName="$__VarValue"
          (( ${4:-0} )) && 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"

Те саме в Windows (як приклад портативності):

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 0

: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 /i "%%j" == "%%i" echo.%%i=%%k
  )
) < "%~2"

exit /b 0

testlock.bat

@echo off

(
  pause
) 9> ./lock

Для запису файлів просто зробіть аналогічний спосіб блокування у коді.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.