สภาพแวดล้อมที่เปลี่ยนแปลงของกระบวนการทำงาน


18

ว่ามันอาจจะเป็นไปได้ที่จะปรับเปลี่ยนตัวแปรบางอย่างในenvการขั้นตอนการทำงานอยู่แล้วเช่นผ่าน/proc/PID/environ?นั่น "แฟ้ม" read-onlyคือ

จำเป็นต้องเปลี่ยนหรือยกเลิกการตั้งค่าตัวแปร DISPLAY ของงานแบ็ตช์ที่รันนานโดยไม่ฆ่ามัน


3
มันสายเกินไปแล้วสำหรับการอ้างอิงในอนาคตxpraอาจจะน่าสนใจ
sr_

xpraฟังดูมีประโยชน์ ปกติผมคำนวณหาเส้นทางที่จะแสดงผู้ใช้ไม่ได้เป็นเจ้าภาพโดยXvfbหรือXephyrแต่วันนี้ฉันลืมและวิ่งออกจาก CLI มากกว่า cron / ที่แก้ไขปัญหาการส่งออกจึงได้รับฉันน่ารำคาญ:0
มาร์กอส

คำตอบ:


19

คุณไม่สามารถทำสิ่งนี้ได้หากปราศจากแฮ็กที่น่ารังเกียจ - ไม่มี API สำหรับสิ่งนี้ไม่มีวิธีแจ้งกระบวนการที่สภาพแวดล้อมมีการเปลี่ยนแปลง (เนื่องจากไม่สามารถทำได้จริง ๆ )
แม้ว่าคุณจะสามารถทำสิ่งนั้นได้ แต่ก็ไม่มีทางที่จะแน่ใจได้ว่ามันจะมีผลกระทบใด ๆ - กระบวนการอาจทำให้แคชตัวแปรสภาพแวดล้อมที่คุณพยายามจะกระตุ้นได้เป็นอย่างดี (เนื่องจากไม่มีสิ่งใดที่จะสามารถเปลี่ยนแปลงได้ )

หากคุณต้องการทำสิ่งนี้จริงๆและพร้อมที่จะรับชิ้นส่วนหากสิ่งผิดปกติคุณสามารถใช้ดีบักเกอร์ได้ ดูตัวอย่างคำถาม Stack Overflow นี้:
มีวิธีการเปลี่ยนตัวแปรสภาพแวดล้อมของกระบวนการอื่นหรือไม่?

เป็นหลัก:

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

ฟังก์ชั่นที่เป็นไปได้อื่น ๆ ที่คุณอาจจะพยายามที่จะโทรหรือsetenvunsetenv

โปรดจำไว้ว่าสิ่งนี้อาจไม่ได้ผลหรือมีผลกระทบร้ายแรงหากกระบวนการที่คุณกำหนดเป้าหมายทำสิ่งที่ "น่าสนใจ" ด้วยบล็อกสภาพแวดล้อม ลองทดสอบกับกระบวนการที่ไม่สำคัญก่อน แต่ให้แน่ใจว่ากระบวนการทดสอบเหล่านี้สะท้อนให้เห็นอย่างใกล้ชิดที่สุดเท่าที่จะเป็นไปได้สำหรับกระบวนการที่คุณพยายามจะกระตุ้น


3
ใช่ฉันรู้ว่ามันค่อนข้างแฮ็คเสี่ยงและไม่รับประกันด้วยเหตุผลที่คุณพูดถึง (ส่วนหนึ่งของเหตุผลที่ฉันเยี่ยมชมกลุ่มนี้มีไว้สำหรับความต้องการที่ไม่ธรรมดาฉันไม่สามารถหาได้ตามปกติ) ในกรณีนี้การตั้งค่า DISPLAY เป็นขยะหรือเปล่าเพียงแค่แก้ไขความรำคาญและความล่าช้า (ภาพหน้าจอที่ไม่จำเป็นบนเครือข่าย พวกเขาล้มเหลว) เนื่องจากเด็กคัดลอกพาเรนต์ฉันต้องแก้ไข parent env เท่านั้น กระบวนการ child & subchild ใหม่ ๆ หลายอย่างกำลังเกิดขึ้นและออกจากงานของฉันอย่างรวดเร็ว เรื่องเหล่านั้น ฉันคิดว่าดีบักเกอร์สามารถทำสิ่งนี้ได้ขอบคุณ - ฉันสามารถห่อมันลงในฟังก์ชันเชลล์ได้
Marcos

0

ไม่จำเป็นต้องทำเช่นนั้นหากงานแบ็ตช์สามารถอ่านได้จากระบบไฟล์เพื่อดึงข้อมูลการเปลี่ยนแปลง เพียงแค่รันงานด้วยพา ธ ไปยังไดเรกทอรีที่ไม่ซ้ำกันชั่วคราวและส่งผ่านพา ธ เดียวกันไปที่ child shell script สคริปต์จะล็อคไฟล์ในไดเรกทอรีนั้นและเขียนไฟล์ที่มีค่าใหม่ใกล้กับไฟล์ล็อค สคริปต์งานเป็นครั้งคราวจะล็อคไฟล์เดียวกันแยกวิเคราะห์และอ่านการเปลี่ยนแปลงกลับจากไฟล์ค่า เพื่อหาวิธีทำการล็อคในยูนิกซ์เชลล์เพียงแค่ค้นหาunix shell lock fileหรือbash lock fileมีวิธีแก้ไขปัญหาอยู่มากมาย

ประโยชน์จากโซลูชันนี้:

  • พกพาได้เกือบทุกระบบปฏิบัติการเช่น Windows หรือ Unix
  • ไม่จำเป็นต้องเขียนและทำซ้ำ parsers ที่ซับซ้อนสำหรับแต่ละล่าม (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

ในการเขียนไฟล์โดยใช้วิธีเดียวกันกับล็อครหัสของคุณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.