ฉันไปรอบ ๆ ด้วยสิ่งนี้ ฉันรู้สึกหงุดหงิดกับการพกพาแบบ null bytes ฉันนั่งไม่ดีกับฉันว่าไม่มีวิธีที่เชื่อถือได้ในการจัดการพวกเขาในเปลือก ดังนั้นฉันจึงดูต่อไป ความจริงก็คือฉันพบหลายวิธีในการทำเช่นนี้มีเพียงไม่กี่ข้อเท่านั้นที่ถูกบันทึกไว้ในคำตอบอื่น ๆ ของฉัน แต่ผลลัพธ์มีฟังก์ชันเชลล์อย่างน้อยสองฟังก์ชันที่ทำงานดังนี้:
_pidenv ${psrc=$$} ; _zedlmt <$near_any_type_of_file
ก่อนอื่นฉันจะพูดเกี่ยวกับการ\0
กำหนด อันที่จริงมันค่อนข้างง่ายที่จะทำ นี่คือฟังก์ชั่น:
_zedlmt() { od -t x1 -w1 -v | sed -n '
/.* \(..\)$/s//\1/
/00/!{H;b};s///
x;s/\n/\\x/gp;x;h'
}
เป็นพื้น od
จะใช้เวลาstdin
และเขียนไปยังstdout
แต่ละไบต์ที่ได้รับเป็นเลขฐานสิบหกต่อหนึ่งบรรทัด
printf 'This\0is\0a\0lot\0\of\0\nulls.' |
od -t x1 -w1 -v
#output
0000000 54
0000001 68
0000002 69
0000003 73
0000004 00
0000005 69
0000006 73
#and so on
ฉันพนันได้เลยว่าคุณเดาได้ว่าอัน\0null
ไหนใช่ไหม? เขียนออกมาเช่นว่ามันจัดการง่ายๆ sed
ด้วยsed
เพียงบันทึกสองตัวอักษรสุดท้ายในแต่ละบรรทัดจนกว่าจะพบค่าว่าง ณ จุดที่มันแทนที่บรรทัดใหม่กลางด้วยprintf
รหัสรูปแบบที่เป็นมิตรและพิมพ์สตริง ผลลัพธ์ที่ได้คือ\0null
อาเรย์ที่คั่นด้วยสตริงสตริง hex ดู:
printf %b\\n $(printf 'Fewer\0nulls\0here\0.' |
_zedlmt | tee /dev/stderr)
#output
\x46\x65\x77\x65\x72
\x6e\x75\x6c\x6c\x73
\x68\x65\x72\x65
\x2e
Fewer
nulls
here
.
ฉันส่งไปด้านบนเพื่อtee
ให้คุณสามารถดูทั้งผลลัพธ์ของคำสั่ง susbstitution และผลลัพธ์ของprintf
การประมวลผล ฉันหวังว่าคุณจะสังเกตเห็นว่าจริง ๆ แล้วการแยกชั้นย่อยไม่ได้ยกมา แต่printf
ยังแยกเพียงที่\0null
ตัวคั่นเท่านั้น ดู:
printf %b\\n $(printf \
"Fe\n\"w\"er\0'nu\t'll\\'s\0h ere\0." |
_zedlmt | tee /dev/stderr)
#output
\x46\x65\x0a\x22\x77\x22\x65\x72
\x27\x6e\x75\x09\x27\x6c\x6c\x27\x73
\x68\x20\x20\x20\x20\x65\x72\x65
\x2e
Fe
"w"er
'nu 'll's
h ere
.
ไม่มีคำพูดในการขยายตัวเช่นกัน - มันไม่สำคัญว่าคุณจะพูดหรือไม่ นี่เป็นเพราะค่าการกัดนั้นผ่านมาไม่ได้แยกออกจากกันยกเว้นค่าการกัด\n
ewline ที่สร้างขึ้นในแต่ละครั้งที่sed
พิมพ์สตริง การแยกคำไม่ได้ใช้ และนั่นคือสิ่งที่ทำให้สิ่งนี้เป็นไปได้:
_pidenv() { ps -p $1 >/dev/null 2>&1 &&
[ -z "${1#"$psrc"}" ] && . /dev/fd/3 ||
cat <&3 ; unset psrc pcat
} 3<<STATE
$( [ -z "${1#${pcat=$psrc}}" ] &&
pcat='$(printf %%b "%s")' || pcat="%b"
xeq="$(printf '\\x%x' "'=")"
for x in $( _zedlmt </proc/$1/environ ) ; do
printf "%b=$pcat\n" "${x%%"$xeq"*}" "${x#*"$xeq"}"
done)
#END
STATE
ฟังก์ชั่นด้านบนใช้_zedlmt
กับ${pcat}
สตรีมโค้ดไบต์ที่เตรียมไว้สำหรับการจัดหาสภาพแวดล้อมของกระบวนการใด ๆ ที่สามารถพบได้ใน/proc
หรือโดยตรง.dot
${psrc}
ในเชลล์ปัจจุบันโดยตรงหรือโดยไม่มีพารามิเตอร์เพื่อแสดงเอาต์พุตที่ประมวลผลเหมือนกับเทอร์มินัลเช่นset
หรือprintenv
จะ สิ่งที่คุณต้องมีคือ$pid
- ไฟล์ใด ๆ ที่อ่านได้/proc/$pid/environ
จะทำ
คุณใช้มันแบบนี้:
#output like printenv for any running process
_pidenv $pid
#save human friendly env file
_pidenv $pid >/preparsed/env/file
#save unparsed file for sourcing at any time
_pidenv ${pcat=$pid} >/sourcable/env.save
#.dot source any pid's $env from any file stream
_pidenv ${pcat=$pid} | sh -c '. /dev/stdin'
#feed any pid's env in on a heredoc filedescriptor
su -c '. /dev/fd/4' 4<<ENV
$( _pidenv ${pcat=$pid} )
ENV
#.dot sources any $pid's $env in the current shell
_pidenv ${psrc=$pid}
แต่อะไรคือความแตกต่างระหว่างความเป็นมิตรของมนุษย์และการหาที่มา ? ความแตกต่างคือสิ่งที่ทำให้คำตอบนี้แตกต่างจากที่อื่น - รวมถึงคำตอบของฉันด้วย ทุกคำตอบอื่น ๆ ขึ้นอยู่กับการอ้างถึงเชลล์ในทางใดทางหนึ่งเพื่อจัดการกับกรณีขอบทั้งหมด มันใช้งานได้ไม่ดี โปรดเชื่อฉัน - ฉันลองดู:
_pidenv ${pcat=$$}
#output
LC_COLLATE=$(printf %b "\x43")
GREP_COLOR=$(printf %b "\x33\x37\x3b\x34\x35")
GREP_OPTIONS=$(printf %b "\x2d\x2d\x63\x6f\x6c\x6f\x72\x3d\x61\x75\x74\x6f")
LESS_TERMCAP_mb=$(printf %b "\x1b\x5b\x30\x31\x3b\x33\x31\x6d")
LESS_TERMCAP_md=$(printf %b "\x1b\x5b\x30\x31\x3b\x33\x31\x6d")
LESS_TERMCAP_me=$(printf %b "\x1b\x5b\x30\x6d")
LESS_TERMCAP_se=$(printf %b "\x1b\x5b\x30\x6d")
LESS_TERMCAP_so=$(printf %b "\x1b\x5b\x30\x30\x3b\x34\x37\x3b\x33\x30\x6d")
LESS_TERMCAP_ue=$(printf %b "\x1b\x5b\x30\x6d")
NOจำนวนตัวอักษรขี้ขลาดหรือมีอยู่ quoting สามารถทำลายนี้เพราะไบต์สำหรับแต่ละค่าไม่ได้ประเมินจนมากทันทีเนื้อหามีที่มา และเรารู้อยู่แล้วว่ามันทำงานเป็นค่าอย่างน้อยหนึ่งครั้ง - ไม่มีการแยกวิเคราะห์หรืออ้างจำเป็นที่นี่เพราะนี่เป็นสำเนาไบต์ต่อไบต์ของค่าเดิม
ฟังก์ชันจะประเมิน$var
ชื่อและรอการตรวจสอบให้เสร็จก่อนที่จะ.dot
จัดหา here-doc ที่ป้อนเข้ามาใน file-descriptor 3 ก่อนที่มันจะมามันเป็นสิ่งที่ดูเหมือน มันโง่เขลา และ POSIX แบบพกพา อย่างน้อยที่สุด \ 0 การจัดการที่ว่างเปล่าเป็น POSIX แบบพกพา - ระบบไฟล์ / กระบวนการนั้นมีความเฉพาะของ Linux และนั่นเป็นเหตุผลที่มีสองฟังก์ชั่น
. <(xargs -0 bash -c 'printf "export %q\n" "$@"' -- < /proc/nnn/environ)
ซึ่งจะจัดการกับตัวแปรด้วยคำพูดในพวกเขาอย่างถูกต้องเช่นกัน