ubah lingkungan proses yang sedang berjalan

18

Bagaimana mungkin mengubah beberapa variabel dalam proses envyang sudah berjalan, misalnya melalui /proc/PID/environ?"file" itu read-only.

Perlu mengubah atau menghapus variabel DISPLAY dari pekerjaan batch yang berjalan lama tanpa membunuhnya.

Marcos
sumber
3
Sudah terlambat sekarang, tetapi untuk referensi di masa depan, xprabisa jadi menarik.
sr_
xprakedengarannya bermanfaat. Biasanya saya mengalihkan rute ke tampilan non-pengguna yang dihosting oleh Xvfbatau Xephyr, tetapi hari ini saya lupa dan lari dari cli daripada cron / at untuk memecahkan masalah keluaran, jadi itu mengganggu saya di:0
Marcos

Jawaban:

19

Anda tidak dapat melakukan ini tanpa peretasan yang buruk - tidak ada API untuk ini, tidak ada cara untuk memberi tahu proses bahwa lingkungannya telah berubah (karena itu sebenarnya tidak mungkin).
Bahkan jika Anda berhasil melakukan itu, tidak ada cara untuk memastikan bahwa itu akan memiliki efek apa pun - proses tersebut dapat dengan sangat baik men-cache variabel lingkungan yang Anda coba tusuk (karena tidak ada yang dapat mengubahnya) ).

Jika Anda benar-benar ingin melakukan ini, dan siap untuk mengambil bagian jika ada yang salah, Anda dapat menggunakan debugger. Lihat misalnya pertanyaan Stack Overflow ini:
Apakah ada cara untuk mengubah variabel lingkungan proses lain?

Pada dasarnya:

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

Fungsi lain yang dapat Anda coba panggil adalah setenvatau unsetenv.

Harap benar-benar diingat bahwa ini mungkin tidak berhasil, atau memiliki konsekuensi yang mengerikan jika proses yang Anda targetkan melakukan hal-hal "menarik" dengan blok lingkungannya. Lakukan pengujian pada proses non-kritis terlebih dahulu, tetapi pastikan proses pengujian ini mencerminkan sedekat mungkin yang Anda coba tusuk.

Tikar
sumber
3
Ya, saya sadar ini agak meretas, berisiko, dan tidak dijamin karena alasan yang Anda sebutkan. (Bagian dari alasan saya mengunjungi grup ini adalah untuk kebutuhan non-konvensional seperti yang sepertinya tidak dapat saya temukan secara normal.) Dalam hal ini mengatur DISPLAY menjadi sampah atau kosong hanya menyelesaikan gangguan dan penundaan (tangkapan layar yang sering tidak perlu melalui jaringan, baik jika mereka gagal). Karena child copy parent, saya hanya perlu mod parent env. Banyak proses anak & anak baru lahir dan keluar dengan cepat dalam pekerjaan batch saya; hal itu. Saya pikir debugger bisa melakukan ini, terima kasih - saya bisa membungkusnya menjadi fungsi shell.
Marcos
0

Tidak perlu melakukannya jika pekerjaan batch dapat membaca dari sistem file untuk mengambil perubahan. Jalankan saja pekerjaan dengan jalur ke direktori unik sementara dan berikan jalur yang sama ke skrip shell anak. Script akan mengunci file di direktori itu dan menulis file dengan nilai baru di dekat file kunci. Skrip pekerjaan dari waktu ke waktu akan mengunci file yang sama, mem-parsing dan membaca perubahan kembali dari file nilai. Untuk mengetahui cara membuat kunci di shell unix hanya mencari unix shell lock fileatau bash lock file, sudah ada banyak solusi untuk itu.

Manfaat dari solusi ini:

  • portabel antara hampir semua OS seperti Windows atau Unix
  • tidak perlu menulis dan menduplikasi parser kompleks untuk setiap penerjemah (unix / windows / dll) untuk membaca kembali nilai-nilai dari file selama file nilai tetap sederhana

Masalah dalam implementasi di bawah ini:

  • Implementasi bergantung pada kunci file dalam fase redirection shell ( flockdi Linux untuk mencapai efek pengecualian, di Windows memiliki built-in exclusion)
  • Setiap nilai untuk suatu variabel adalah nilai baris tunggal (bukan multiline)

Implementasi disimpan di sini: https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Scripts/Tools

The bashimplementasi:

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"

Hal yang sama pada Windows (sebagai contoh portabilitas):

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

Untuk menulis file hanya dengan cara yang sama mengunci kode Anda.

Andry
sumber