วิธี distro / shell-agnostic ที่ดีที่สุดในการตั้งค่าตัวแปรสภาพแวดล้อมคืออะไร


31

คำถามบอกว่ามันทั้งหมด ปัจจุบันฉันใช้ Arch Linux และ zsh แต่ฉันต้องการวิธีแก้ปัญหาที่ (อย่างน้อยที่สุด) ใช้งานได้ทั้งบน VT และใน xterms และ (หวังว่าควรเป็นอย่างยิ่ง) จะยังคงทำงานต่อไปถ้าฉันเปลี่ยน distros หรือ shell

ฉันได้ยินว่าคำตอบของคำถามนี้แตกต่างกันอย่างมากในเอกสารของ distros ที่แตกต่างกัน Ubuntu บอกว่า "ใช้. pam_environment" ฉันคิดว่าใน Arch สิ่งที่พวกเขาแนะนำขึ้นอยู่กับเปลือกของคุณ ขณะนี้ฉันใส่ทุกอย่างใน. profileและถ้าเชลล์ไม่ได้แหล่งที่มาด้วยเหตุผลบางอย่าง (เช่นทุบตีถ้า. bash_profile มีอยู่) ฉันจะแทนที่ด้วยการจัดหามันด้วยตนเอง แต่ดูเหมือนว่าจะต้องมีวิธีที่ดีกว่า


2
สิ่งนี้ไม่เกี่ยวกับ distro และทุกอย่างเกี่ยวกับเชลล์ ไม่แน่ใจว่ามีวิธีพกพาที่ต้องทำ
โจเซฟอาร์

อืมมม เยี่ยมมาก
strugee

คำตอบ:


29

โชคไม่ดีที่ไม่มีตำแหน่งแบบพกพาในการตั้งค่าตัวแปรสภาพแวดล้อม ไฟล์สองไฟล์ที่ใกล้เคียงที่สุดคือ~/.profileซึ่งเป็นตำแหน่งดั้งเดิมและทำงานนอกกรอบในการตั้งค่าจำนวนมากและ~/.pam_environmentเป็นทางเลือกที่ทันสมัยธรรมดา แต่มีข้อ จำกัด

สิ่งที่ควรใส่ ~/.pam_environment

ไฟล์~/.pam_environmentถูกอ่านโดยวิธีการเข้าสู่ระบบทั้งหมดที่ใช้PAMและเปิดใช้งานไฟล์นี้ ซึ่งครอบคลุมระบบ Linux ส่วนใหญ่ในปัจจุบัน

ข้อได้เปรียบที่สำคัญของ~/.pam_environmentมันคือ (เมื่อเปิดใช้งาน) มันถูกอ่านก่อนที่เชลล์ของผู้ใช้จะเริ่มทำงานดังนั้นจึงทำงานได้โดยไม่คำนึงถึงประเภทเซสชัน, ล็อกอินเชลล์และความซับซ้อนอื่น ๆ มันยังทำงานสำหรับการเข้าสู่ระบบไม่โต้ตอบเช่นและsu -c somecommandssh somecommand

ข้อ จำกัด ที่สำคัญ~/.pam_environmentคือคุณสามารถกำหนดได้ง่าย ๆ เท่านั้นไม่ใช่ไวยากรณ์เชลล์ที่ซับซ้อน ไวยากรณ์ของไฟล์นี้เป็นดังนี้

  • ไฟล์จะถูกวิเคราะห์คำทีละบรรทัด
  • ช่องว่างนำหน้าจะถูกละเว้น
  • คุณสามารถเลือกที่จะเริ่มต้นบรรทัดด้วยexportและเว้นวรรคเดียว (ไม่ใช่แท็บ, ไปคิดเลข)
  • หลังจากนั้นแต่ละบรรทัดจะต้องมีรูปแบบVAR=VALUEที่ VAR ประกอบด้วยตัวอักษรตัวเลขและขีดล่าง
  • # เริ่มความคิดเห็นมันไม่สามารถปรากฏในค่า
  • หาก VALUE เริ่มต้นด้วย'หรือ"และมีเครื่องหมายคำพูดเหมือนกันอีกข้อความหนึ่ง VAR จะถูกตั้งค่าเป็นสตริงระหว่างเครื่องหมายคำพูด (ทุกอย่างหลังจากเครื่องหมายคำพูดที่สองถูกละเว้น) มิฉะนั้น VAR จะถูกตั้งค่าเป็นสตริงหลัง=เครื่องหมาย
  • หากไม่มี=อยู่ตัวแปรจะถูกลบออกจากสภาพแวดล้อม

กลับหัวกลับหาง~/.pam_environmentทำงานในสถานการณ์มากมาย ในข้อเสียคุณไม่สามารถมีการตั้งค่าแบบไดนามิกใด ๆ เช่นฐานค่าของตัวแปรกับตัวแปรอื่น (เช่นการเพิ่มไดเรกทอรีไปยัง PATH) หรือใช้ผลลัพธ์ของคำสั่ง (เช่นทดสอบว่ามีไดเรกทอรีหรือโปรแกรม) และบางส่วน อักขระ ( #'"ขึ้นบรรทัดใหม่) เป็นไปไม่ได้หรือมีปัญหาในการใส่ค่า

สิ่งที่ควรใส่ ~/.profile

ไฟล์นี้ควรมีไวยากรณ์ sh (พกพา) แบบพกพา เพียงใช้ ksh หรือทุบตีส่วนขยาย (อาร์เรย์[[ … ]]ฯลฯ ) /bin/shถ้าคุณรู้ว่าระบบของคุณมีเปลือกหอยเหล่านี้เป็น

แฟ้มนี้อาจจะอ่านโดยสคริปต์ในการใช้งานอัตโนมัติจึงไม่ควรเรียกโปรแกรมที่ผลิตออกใด ๆ execหรือโทร หากคุณต้องการทำเช่นนั้นในการเข้าสู่ระบบโหมดข้อความให้ทำสำหรับเชลล์แบบโต้ตอบเท่านั้น ตัวอย่าง:

case $- in *i*)
  # Display a message if I have new mail
  if mail -e; then echo 'You have new mail'; fi
  # If zsh is available, and this looks like a text-mode login, run zsh
  case "`ps $PPID` " in
    *" login "*)
      if type zsh >/dev/null 2>/dev/null; then exec zsh; fi;;
  esac
esac

นี่เป็นตัวอย่างของการใช้/bin/shเป็นเชลล์ล็อกอินของคุณและเปลี่ยนเป็นเชลล์ที่คุณชื่นชอบ ดูเพิ่มเติมว่าฉันจะใช้ทุบตีเป็นเปลือกเข้าสู่ระบบของฉันอย่างไรเมื่อระบบดูแลระบบของฉันปฏิเสธที่จะให้ฉันเปลี่ยน

เมื่อ~/.profileไม่อ่านในการเข้าสู่ระบบที่ไม่ใช่กราฟิก?

ที่แตกต่างกันหอยเข้าสู่ระบบอ่านไฟล์ที่แตกต่างกัน

หากเปลือกเข้าสู่ระบบของคุณเป็นทุบตี

ทุบตีอ่าน~/.bash_loginหรือถ้าพวกเขามีอยู่แทน~/.bash_profile ~/.profileนอกจากนี้ bash จะไม่อ่าน~/.bashrcในเชลล์ล็อกอินแม้ว่ามันจะเป็นแบบโต้ตอบ หากไม่ต้องการจดจำข้อผิดพลาดเหล่านี้อีกให้สร้าง a ~/.bash_profileด้วยสองบรรทัดต่อไปนี้:

. ~/.profile
case $- in *i*) . ~/.bashrc;; esac

ดูเพิ่มเติมไฟล์ตั้งค่าใดที่ควรใช้สำหรับตั้งค่าตัวแปรสภาพแวดล้อมด้วย bash

หากเชลล์ล็อกอินของคุณคือ zsh

zsh อ่าน~/.zprofileและแต่ไม่~/.zlogin ~/.profileZsh มีรูปแบบที่แตกต่างจาก sh แต่สามารถอ่านได้~/.profileในโหมดem sh คุณสามารถใช้สิ่งนี้เพื่อ~/.zprofile:

emulate sh -c '. ~/.profile'

ดูZsh ด้วยไม่กดปุ่ม ~ / .profile

หากเปลือกเข้าสู่ระบบของคุณเป็นเปลือกอื่น ๆ

มีไม่มากที่คุณสามารถทำได้มีเพียงการใช้/bin/shเชลล์การเข้าสู่ระบบและเชลล์ที่คุณโปรดปราน (เช่นปลา) เป็นเชลล์เชิงโต้ตอบเท่านั้น นั่นคือสิ่งที่ฉันทำกับ zsh ดูตัวอย่างการเรียกเชลล์อื่นจากด้าน~/.profileบน

คำสั่งระยะไกล

เมื่อเรียกใช้คำสั่งระยะไกลโดยไม่ต้องผ่านเชลล์แบบโต้ตอบเชลล์บางตัวเท่านั้นที่อ่านไฟล์เริ่มต้น

Ksh อ่านไฟล์ที่ระบุโดยENVตัวแปรหากคุณจัดการเพื่อส่งผ่าน

ทุบตีอ่าน~/.bashrcถ้ามันเป็นไม่ได้โต้ตอบ (!) และการปกครองของมันจะถูกเรียกว่าหรือrshd sshdดังนั้นคุณสามารถเริ่มต้น~/.bashrcด้วย

if [[ $- != *i* ]]; then
  . ~/.profile
  return
fi

Zsh มักจะอ่าน~/.zshenvเมื่อมันเริ่ม ใช้ด้วยความระมัดระวังเนื่องจากสิ่งนี้จะถูกอ่านโดยทุก ๆ อินสแตนซ์ของ zsh แม้ว่ามันจะเป็น subshell ที่คุณตั้งค่าตัวแปรอื่น ๆ หาก zsh เป็นเปลือกเข้าสู่ระบบของคุณและคุณต้องการที่จะใช้กับตัวแปรชุดเท่านั้นสำหรับคำสั่งระยะไกลใช้ยาม: ตั้งค่าตัวแปรบางอย่างใน~/.profileเช่นMY_ENVIRONMENT_HAS_BEEN_SET=yes, ~/.profileและตรวจสอบยามนี้ก่อนที่จะอ่าน

if [[ -z $MY_ENVIRONMENT_HAS_BEEN_SET ]]; then emulate sh -c '~/.profile'; fi

กรณีของการเข้าสู่ระบบแบบกราฟิก

ดิสทริบิวเตอร์และสภาพแวดล้อมเดสก์ท็อปจำนวนมากจัดเตรียมให้ทำงาน~/.profileโดยการจัดหาอย่างชัดเจนจากสคริปต์เริ่มต้นหรือโดยใช้เชลล์ล็อกอิน

น่าเสียดายที่ไม่มีวิธีทั่วไปในการจัดการชุด distro / DM / DE ที่~/.profileไม่ได้อ่าน

หากคุณใช้เซสชันดั้งเดิมที่เริ่มโดยที่~/.xsessionนี่เป็นสถานที่ที่คุณควรตั้งค่าตัวแปรสภาพแวดล้อมของคุณ ทำได้โดยการจัดหา~/.profile(เช่น. ~/.profile) โปรดทราบว่าในการตั้งค่าบางอย่างสคริปต์เริ่มต้นสภาพแวดล้อมเดสก์ท็อปจะมา~/.profileอีกครั้ง


สิ่งที่ไม่case $- in *i*)ทำอะไร?
qodeninja

2
@qodeninja ดำเนินการตามคำแนะนำต่อไปนี้ (จนกว่าจะมีการจับคู่;;หรือesac) หาก$-ตรงกับรูปแบบ*i*เช่นถ้า$-มีi, เช่นถ้าเปลือกเป็นแบบโต้ตอบ
Gilles 'SO- หยุดความชั่วร้าย'

$-เป็นสตริงของตัวเลือกเชลล์ที่ตั้งค่าไว้ในปัจจุบัน (ชอบset -x) iหมายถึงเปลือกโต้ตอบ
Peter Cordes

คุณไม่สามารถเพียงแค่ส่งไฟล์ทั่วไปให้พูด~/.config/envแม้ว่าจะไม่มีอีมูเลชันหรือไม่
Kevin Suttle

1
@ StéphaneChazelasนั่นเป็นมุมมองที่พิถีพิถัน ฉันรักษาความ.profileสอดคล้องกับ Bourne shell ที่ค่อนข้างเก่า แต่ฉันรู้ว่าบางคนไม่สนใจ ฉันไม่มีอะไรกับคนที่คิดว่า sh = bash สำหรับไฟล์ของตัวเองฉันจะสนใจก็ต่อเมื่อพวกเขาเผยแพร่#!/bin/shสคริปต์ที่ใช้คุณสมบัติทุบตี
Gilles 'หยุดความชั่วร้าย' ใน

4

เท่าที่ฉันรู้ไม่มีมาตรฐานผู้ไม่เชื่อเรื่องพระเจ้า distro และ shell วิธีตั้งค่าตัวแปรสภาพแวดล้อม

ที่พบมากที่สุดและพฤตินัยมาตรฐานน่าจะเป็นและ/etc/profile ~/.profileที่พบมากที่สุดที่สองน่าจะเป็นและ/etc/environment~/.pam_environment

ดูเหมือนว่าฉันว่าเอกสารทั้งหมดที่ฉันพบคุณก็พบแล้ว ฉันจะแสดงรายการไว้ที่นี่สำหรับผู้อ่านรายอื่น

  • เดเบียนแนะนำ/etc/profileและ~/.profile( ลิงก์ )
  • Ubuntu แนะนำ/etc/environmentและ~/.pam_environment( ลิงก์ )
  • Arch Linux กล่าวถึงกลุ่มอื่น ๆ/etc/profileและ/etc/environment( ลิงก์ )

โบนัส: ข้อความที่ถามถึงการใช้งานและ / หรือการใช้งานที่ไม่ถูกต้อง/etc/environmentในเดเบียน ( ลิงก์ , อัปเดตล่าสุด 2008)


ไม่ว่าไฟล์ที่คุณใช้จะยังคงชนกับไวยากรณ์ที่เข้ากันไม่ได้ระหว่างเชลล์ที่แตกต่างกัน
โจเซฟอาร์

1
@JosephR เปลือกหอยส่วนใหญ่ไม่รองรับการใช้งานย้อนหลังshหรือไม่ ตราบใดที่คุณติด POSIX ผมจะมีความคิดที่คุณต้องการจะปรับ ...
evilsoup

1
AFAIK คุณไม่สามารถกำหนดตัวแปรในcshและเพื่อน ๆ ในแบบ POSIX (คุณต้องการอะไรเช่นsetหรือsetenv)
โจเซฟอาร์

0

ฉันเพิ่มสคริปต์ ~ / bin / agnostic_setenv ต่อไปนี้:

#!/bin/csh -f
set args = ($*)
if ($#args == 1) then
   echo "export $args[1]="
   exit 0
endif

if ($#args == 2) then
   if ("$args[1]" =~ *csh*) then 
      echo "setenv $args[2]"
      exit 0
   else
      echo "export $args[1]=$args[2]"
      exit 0
   endif
endif

echo "setenv $args[2] $args[3]"

และใน ~ / .perl-homedir ฉันใช้:

eval `${HOME}/bin/agnostic_setenv $shell PERL_HOMEDIR 0`

สคริปต์ที่คล้ายกันสำหรับ agnostic_unsetenv:

#!/bin/csh -f
set args = ($*)
if ($#args == 1) then
   echo "export $args[1]"
   exit 0
endif

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