เชลล์ posix: รายการพิมพ์ของชื่อตัวแปรสภาพแวดล้อม (ไม่มีค่า)


11

ในวิธีที่เข้ากันได้กับ posix ที่ทำงานกับการใช้งานหลายอย่างฉันจะพิมพ์รายการตัวแปรสภาพแวดล้อมที่กำหนดไว้ในปัจจุบันโดยไม่มีค่าได้อย่างไร

ในการใช้งานบางอย่าง (mksh, freebsd / bin / sh) เพียงแค่ใช้exportด้วยตัวเองจะพอดีกับการเรียกเก็บเงิน:

$ export
FOO2
FOO

แต่สำหรับการปรับใช้อื่น ๆ (bash, zsh, dash) exportก็แสดงค่าเช่นกัน ด้วย bash ตัวอย่างเช่น:

$ export
export FOO2='as  df\
  asdk=fja:\
asd=fa\
asdf'
export FOO='sjfkasjfd  kjasdf:\
   asdkj=fkajdsf:\
       :askjfkajsf=asdfkj:\
   safdkj'
$ printenv | sed -n l
FOO2=as\tdf\$
  asdk=fja:\$
asd=fa\$
asdf$
FOO=sjfkasjfd  kjasdf:\$
   asdkj=fkajdsf:\$
\t:askjfkajsf=asdfkj:\$
   safdkj$

ตัวเลือกอื่น ๆ เช่นenvหรือprintenvไม่มีตัวเลือกในการพิมพ์เพียงชื่อตัวแปรโดยไม่มีค่าอย่างน้อยก็ไม่ได้อยู่บนแพลตฟอร์ม linux และ freebsd ที่ฉันได้ลอง

ท่อไปที่ awk / sed / etc หรือตัดรายการด้วยเทคนิคการขยายพารามิเตอร์ (เช่น, ${foo%%=*}) เป็นที่ยอมรับ แต่ต้องทำงานกับค่าที่อาจขยายบรรทัดและมี=และช่องว่างในค่า (ดูตัวอย่างด้านบน)

คำตอบเฉพาะสำหรับการใช้งานเชลล์โดยเฉพาะนั้นน่าสนใจ แต่ในเบื้องต้นฉันกำลังมองหาบางอย่างที่เข้ากันได้กับการใช้งาน


2
หากคุณกำลังจะแยกวิเคราะห์บางสิ่งให้ไปกับเอาต์พุตexport -pที่ POSIX ระบุเพื่อสร้างเอาต์พุตที่เหมาะสำหรับอินพุตในเชลล์
Kusalananda

ฉันไม่ต้องการอะไรเลยในการป้อนข้อมูลลงในเชลล์ ฉันแค่ต้องการชื่อของตัวแปรสภาพแวดล้อม ดังนั้น cruft พิเศษ (เช่นคำว่า 'export' ที่ด้านหน้าของแต่ละบรรทัด) จะต้องถูกลบออกไป ทำไมฉันถึงต้องการใช้export -pสำหรับสิ่งนี้?
Juan

1
คุณต้องการใช้export -pเพราะนั่นจะให้ผลลัพธ์ที่สอดคล้องกับเชลล์ POSIX ทั้งหมดซึ่งคุณบอกว่าคุณต้องการ
Kusalananda

ฉันต้องการโซลูชันที่จะพิมพ์เฉพาะชื่อตัวแปรที่เป็นโซลูชันที่สอดคล้องกันข้ามเชลล์ export -pไม่ตรงกับข้อกำหนดแรก - การพิมพ์เพียงชื่อตัวแปรโดยไม่มีค่า
ฮวน

หากexport -pคุณกำลังจะไปสิ่งที่แยกไปกับการส่งออกของ ฉันจะไม่เขียนการแยกวิเคราะห์นั้นเพราะในกรณีทั่วไปจะต้องทำการแยกวิเคราะห์คำพูดที่เหมาะสมในกรณีที่คุณมีตัวแปรที่มีค่าเป็นเช่นhello\nexport var=valueนั้น หนึ่งในไม่กี่คำสั่งอื่น ๆ ที่จะให้ผลผลิตที่สอดคล้องกันในทุกเปลือก POSIX เป็นenvแต่ผลลัพธ์ที่ยากที่จะแยกเพราะมันขาดexport =บิต
Kusalananda

คำตอบ:


9

มันค่อนข้างง่ายใน awk

awk 'BEGIN{for(v in ENVIRON) print v}'

อย่างไรก็ตามระวังการใช้งาน awk บางอย่างเพิ่มตัวแปรสภาพแวดล้อมของตัวเอง (เช่น GNU awk เพิ่มAWKPATHและAWKLIBPATHเพื่อENVIRON)

เอาต์พุตไม่ชัดเจนหากชื่อของตัวแปรสภาพแวดล้อมมีการขึ้นบรรทัดใหม่ซึ่งผิดปกติอย่างมาก แต่เป็นไปได้ทางเทคนิค วิธีการแก้ปัญหาที่บริสุทธิ์จะเป็นเรื่องยาก ทางออกที่ดีที่สุดของคุณคือการเริ่มต้นด้วยการexport -pนวดใน sh บริสุทธิ์เป็นเรื่องยาก คุณสามารถใช้ sed เพื่อนวดผลลัพธ์จากexport -pนั้นใช้evalเพื่อรับ shell เพื่อลบสิ่งที่ยกมา Bash และ zsh พิมพ์คำนำหน้าที่ไม่ได้มาตรฐาน

report () { echo "${1%%=*}"; };
eval "$(export -p | sed "s/^export /report /;
                         s/^declare -x /report /;
                         s/typeset -x /report /")"

โปรดทราบว่าขึ้นอยู่กับเชลล์export -pอาจหรือไม่อาจแสดงตัวแปรที่มีชื่อไม่ถูกต้องในเปลือกและถ้ามันไม่ได้แล้วมันอาจหรืออาจไม่พูดชื่ออย่างถูกต้อง ตัวอย่างเช่นตัวแปร dash, mksh และ zsh ละเว้นชื่อที่มี newline, BusyBox dash และ ksh93 พิมพ์ข้อมูลดิบและ bash พิมพ์ข้อมูลดิบโดยไม่มีค่า หากคุณจำเป็นต้องป้องกันการป้อนข้อมูลที่ไม่น่าเชื่อถือไม่ต้องพึ่งพาการแก้ปัญหา POSIX บริสุทธิ์และแน่นอนไม่ได้เรียกในสิ่งที่ได้มาจากการส่งออกของevalexport -p


ฉันไม่แน่ใจว่ามันเป็น "ง่าย" จริง ๆ กับ sed (1) ด้วยค่าหลายบรรทัด - ฉันต้องการดูสิ่งนั้น แต่ขอบคุณสำหรับวิธี awk (1) ฉันคิดว่านี่เป็นวิธีที่พกพาได้มากที่สุด (แม้ว่าฉันไม่คิดว่าexitจำเป็น)
Juan

โปรดทราบว่าหากคุณได้รับFOO<newline>BARคุณไม่ทราบว่าเป็นFOO<newline>BARตัวแปรสภาพแวดล้อม (ซึ่งexport -pจะไม่แสดงด้วยเชลล์ส่วนใหญ่ดูenv $'FOO\nBAR=test' awk 'BEGIN{for (v in ENVIRON) print v}') หรือทั้งสองตัวแปรFOOและBARสภาพแวดล้อม
Stéphane Chazelas

โปรดทราบว่า GNU awkตั้งค่าตัวแปรสภาพแวดล้อมของตัวเอง ( AWKPATHและAWKLIBPATHในระบบของฉัน)
Stéphane Chazelas

@ StéphaneChazelas - ใหม่: ฝังตัวขึ้นบรรทัดใหม่ในชื่อ var - ตกลง - ยากที่จะป้องกันด้วยรหัสเชลล์ Re: AWKPATH & AWKLIBPATH มลภาวะฉันสังเกตเห็นว่าการใส่ร้ายกาจเช่นกัน นั่นคือ gnu awk ไม่ใช่ bsd awk
Juan

0

ฉันชอบสิ่งที่เรียบง่าย สิ่งนี้จะใช้ได้กับระบบ POSIX:

printenv | sed 's;=.*;;' | sort
HOME
HOSTNAME
PATH
PWD
SHLVL
TERM

5
export AAA=$'multi\nBBB=line'
roaima

@todd_dsm - สิ่งนี้ล้มเหลวสำหรับตัวแปรสภาพแวดล้อมที่มีค่าที่ครอบคลุมมากกว่าหนึ่งบรรทัด (เช่นบางครั้ง TERMCAP - ฉันเห็นสิ่งนี้เมื่ออยู่ในหน้าจอ (1) เซสชัน, IIRC) ดังนั้นคำตอบนี้ไม่ตรงตามข้อกำหนดที่อธิบายไว้ในคำถามเดิม ฉันชอบแบบง่าย ๆ แต่ก็ใช้งานไม่ได้
Juan

compgen -eอาหารอันโอชะที่คุณแก้ไขออกมาในโพสต์ต้นฉบับของคุณเป็นที่น่าสนใจสำหรับการทุบตี: มันไม่ได้ช่วยสำหรับการเขียนสคริปต์แบบพกพาของฉัน (เช่นเมื่อไม่มี bash) แต่ก็น่าสนใจ
Juan

แค่อยากรู้อยากเห็นทำไม จำกัด ตัวเองไว้กับเปลือก bourne (posix)? การเป็นไปตามมาตรฐาน posix นั้นยอดเยี่ยม แต่คุณสูญเสียฟังก์ชันการทำงานจำนวนมากในการติดตาม คุณสามารถพกพาได้และไม่รองรับการทุบตี; มันเป็นส่วนหนึ่งของตระกูล GNU
todd_dsm

ใช้dashใน debian ฉันได้รับผลลัพธ์เดียวกันกับคำสั่งด้านบนหรือแก้ไขprintenv | sed 's;*=.;;' | sortเพื่อรับค่า ฉันส่งออกตัวแปรyoและกำหนดความคิดเห็นแรกของคุณด้านบน มันพิมพ์ตามที่คาดไว้มีหลายบรรทัด ไม่แน่ใจว่าสิ่งที่คุณกำลังประสบอยู่ แต่ไม่ควรตัดทอนผลลัพธ์ รันคำสั่งในเชลล์; สิ่งที่มันออกมามีวิธีการทำงาน; คาดว่าจะไม่มีการตัดทอน จากนั้นภายในบริบทของ TERMCAP / screen / iirc; ควรเหมือนกัน หากผลลัพธ์ไม่ตรงกันอาจเป็นปัญหากับหนึ่งในโปรแกรมเหล่านั้น
todd_dsm
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.