ฉันรู้ว่าอาจมีการถามก่อนหน้านี้ แต่ฉันไม่พบมันด้วย Google
ป.ร. ให้ไว้
- เคอร์เนล Linux
- ไม่มีการกำหนดค่าที่เปลี่ยนแปลง $ HOME
- ทุบตี
จะ~ == $HOME
เป็นจริงหรือ
echo "~"
echo "$HOME"
~
$HOME
: P
ฉันรู้ว่าอาจมีการถามก่อนหน้านี้ แต่ฉันไม่พบมันด้วย Google
ป.ร. ให้ไว้
จะ~ == $HOME
เป็นจริงหรือ
echo "~"
echo "$HOME"
~
$HOME
: P
คำตอบ:
สิ่งสำคัญที่ต้องเข้าใจคือ~
การขยายเป็นคุณลักษณะของเชลล์ (ของเชลล์บางตัว) มันไม่ใช่ตัวอักษรเวทมนต์มากกว่าที่จะหมายถึงโฮมไดเร็กตอรี่ที่คุณใช้
มันถูกขยาย (โดยเชลล์ซึ่งเป็นแอ็พพลิเคชันที่ใช้ตีความบรรทัดคำสั่ง) เช่น$var
ถูกขยายเป็นค่าภายใต้เงื่อนไขบางอย่างเมื่อใช้ในบรรทัดคำสั่งเชลล์ก่อนที่คำสั่งจะถูกดำเนินการ
คุณสมบัติดังกล่าวปรากฏตัวครั้งแรกใน C-shell ในช่วงปลายทศวรรษ 1970 (บอร์นเชลล์ไม่ได้มีหรือไม่ได้เป็นรุ่นก่อนหน้าของ ธ อมป์สันเชลล์) ถูกเพิ่มเข้ามาใน Korn เชลล์ (เชลล์ใหม่ที่สร้างขึ้นบนเชลล์ Bourne ใน 80) ในที่สุดมันก็มาตรฐานโดย POSIX และตอนนี้ที่มีอยู่ในเปลือกหอยส่วนใหญ่รวมทั้งคนที่ไม่ใช่ POSIX fish
เช่น
เนื่องจากมันมีการใช้งานอย่างแพร่หลายในเชลล์แอปพลิเคชันที่ไม่ใช่เชลล์บางตัวจึงรับรู้ได้ว่ามันหมายถึงโฮมไดเร็กตอรี่ นั่นคือกรณีที่มีการใช้งานจำนวนมากในแฟ้มการกำหนดค่าของพวกเขาหรือพวกเขาเองบรรทัดคำสั่ง ( mutt
, slrn
, vim
... )
bash
โดยเฉพาะ (ซึ่งเป็นเชลล์ของโครงการ GNU และใช้กันอย่างแพร่หลายในหลายระบบปฏิบัติการบน Linux) เมื่อมีการเรียกใช้sh
นั้นส่วนใหญ่จะเป็นไปตามกฎ POSIXเกี่ยวกับ~
การขยายตัวและในพื้นที่ที่ไม่ได้ระบุไว้โดย POSIX พฤติกรรมส่วนใหญ่จะเหมือนกับ Korn เชลล์ ซึ่งมันเป็นส่วนโคลน)
ขณะที่$var
ถูกขยายในสถานที่ส่วนใหญ่ (ยกเว้นในเครื่องหมายคำพูดเดียว) ~
การขยายการคิดภายหลังจะขยายในเงื่อนไขเฉพาะบางอย่างเท่านั้น
มันจะขยายตัวเมื่ออาร์กิวเมนต์ของตัวเองในรายการบริบทในบริบทที่คาดว่าสตริง
นี่คือตัวอย่างบางส่วนของที่ขยายในbash
:
cmd arg ~ other arg
var=~
var=x:~:x
(ต้องการโดย POSIX ใช้สำหรับตัวแปรเช่นPATH
, MANPATH
... )for i in ~
[[ ~ = text ]]
[[ text = ~ ]]
(การขยายตัวของ~
การถ่ายเป็นรูปแบบใน AT&T ksh
แต่ไม่ใช่bash
ตั้งแต่ 4.0)case ~ in ~) ...
${var#~}
(แม้ว่าจะไม่ได้อยู่ในกระสุนอื่น ๆ )cmd foo=~
(แม้ว่าจะไม่ใช่เมื่อถูกเรียกเป็นsh
และเฉพาะเมื่อสิ่งที่อยู่ทางด้านซ้ายของ=
มีรูปร่างเหมือนbash
ชื่อตัวแปรที่ไม่ได้กล่าวถึง)cmd ~/x
(ต้องการโดย POSIX อย่างเห็นได้ชัด)cmd ~:x
(แต่ไม่ใช่x:~:x
หรือx-~-x
)a[~]=foo; echo "${a[~]} $((a[~]))"
(ไม่ได้อยู่ในเปลือกหอยอื่น ๆ )นี่คือตัวอย่างบางส่วนที่ไม่ได้ขยาย:
echo "~" '~'
echo ~@ ~~
(โปรดทราบว่า~u
มีไว้เพื่อขยายไปยังโฮมไดเร็กตอรี่ของผู้ใช้u
)echo @~
(( HOME == ~ ))
, $(( var + ~ ))
extglob
: case $var in @(~|other))...
(แม้ว่าcase $var in ~|other)
จะตกลง)./configure --prefix=~
(เนื่องจาก--prefix
ไม่ใช่ชื่อตัวแปรที่ถูกต้อง)cmd "foo"=~
(ในbash
เพราะคำพูด)sh
: export "foo"=~
, env JAVA_HOME=~ cmd
...สำหรับสิ่งที่มันขยายเป็น: ~
เพียงอย่างเดียวขยายไปยังเนื้อหาของHOME
ตัวแปรหรือเมื่อไม่ได้ตั้งค่าไว้ที่โฮมไดเร็กทอรีของผู้ใช้ปัจจุบันในฐานข้อมูลบัญชี (เป็นส่วนขยายเนื่องจาก POSIX ทำให้พฤติกรรมนั้นไม่ได้กำหนดไว้)
ควรสังเกตว่าใน ksh88 และbash
เวอร์ชันก่อนหน้า 4.0 การขยายตัวหนอนจะได้รับการทำให้เป็นวงกลม(การสร้างชื่อไฟล์) ในบริบทรายการ:
$ bash -c 'echo "$HOME"'
/home/***stephane***
$ bash -c 'echo ~'
/home/***stephane*** /home/stephane
$ bash -c 'echo "~"'
~
ที่ไม่ควรมีปัญหาในกรณีปกติ
โปรดทราบว่าเนื่องจากมีการขยายคำเตือนเดียวกันจะมีผลกับการขยายรูปแบบอื่น ๆ
cd ~
ไม่ทำงานหาก$HOME
เริ่มต้นด้วย-
หรือมี..
ส่วนประกอบ ดังนั้นแม้ว่าจะไม่สร้างความแตกต่างใด ๆ เลย แต่การพูดอย่างเคร่งครัดควรเขียนว่า:
cd -P -- ~
หรือแม้กระทั่ง:
case ~ in
(/*) cd -P ~;;
(*) d=~; cd -P "./$d";;
esac
(เพื่อครอบคลุมค่าที่$HOME
ต้องการ-
, +2
... ) หรือเพียงแค่:
cd
(ตามที่cd
นำคุณไปสู่โฮมไดเร็กตอรี่โดยไม่มีอาร์กิวเมนต์)
กระสุนอื่น ๆ มี~
การขยายเพิ่มเติมขั้นสูง ตัวอย่างเช่นในzsh
เรามี:
~4
, ~-
, ~-2
(ด้วยความสมบูรณ์) ที่ใช้ในการขยายไดเรกทอรีในกองไดเรกทอรีของคุณ (สถานที่ที่คุณเคยcd
ไปมาก่อน)~something
จะขยายตัวอย่างไรในรุ่นใด ๆ ของทุบตีในระบบใด ๆ ใช่ ~
เป็นคำที่ตัวเองถูกกำหนดให้ขยายไปยัง:
ค่าของ $ HOME
ดังนั้นมันจะเหมือนกับสิ่งที่$HOME
อยู่ในเชลล์ปัจจุบันเสมอ มีการขยายตัวหนอนอื่น ๆ อีกหลายอย่างเช่น~user
สำหรับuser
โฮมไดเร็กตอรี่~
ของ, แต่สิ่งที่ไม่ได้กล่าวถึงในตัวมันจะขยายออกไป"$HOME"
เสมอ
โปรดทราบว่าพฤติกรรมของ~
และ$HOME
สามารถแตกต่างกันได้ในบางกรณี: โดยเฉพาะถ้า$HOME
มีช่องว่าง (หรืออักขระIFSอื่น ๆ) จากนั้น$HOME
(ไม่พูดถึง) จะขยายออกเป็นหลายคำในขณะที่~
เป็นคำเดียวเสมอ ~
ขยายเท่ากับ"$HOME"
(ที่ยกมา)
สำหรับคำถามเฉพาะของคุณ:
[[ $HOME == ~ ]]
เป็นจริงเสมอเพราะ[[
ยับยั้งการแยกคำ [[ ~ == $HOME ]
อาจจะไม่ได้ถ้าHOME
มีตัวอักษรที่ตรงกับรูปแบบในมัน แต่[[ ~ == "$HOME" ]]
(เช่นที่ยกมา"$HOME"
) เป็นจริงเสมอ การใช้ภายในวงเล็บปีกกาเดียวอาจเป็นข้อผิดพลาดทางไวยากรณ์สำหรับค่าของการHOME
เว้นวรรคหรืออักขระพิเศษ สำหรับการกำหนดค่าโฮมไดเรกทอรีที่สมเหตุสมผลใด ๆ~
และ"$HOME"
เหมือนกันและเปรียบเทียบเท่ากัน
Stéphane Chazelas ได้บันทึกกรณีในความคิดเห็นที่~
และ$HOME
ให้ค่าที่แตกต่าง: ถ้าคุณunset HOME
แล้วเมื่อคุณใช้~
Bash จะโทรgetpwuid
เพื่ออ่านค่าออกจากฐานข้อมูลรหัสผ่าน กรณีนี้ไม่รวมอยู่ในเงื่อนไขที่คุณไม่มีการเปลี่ยนแปลงการกำหนดค่า$HOME
แต่ฉันจะพูดถึงเรื่องนี้เพื่อความสมบูรณ์
/bin/sh
bash
ฉันไม่แน่ใจว่าsh
ข้อมูลจำเพาะของPosix บอกเกี่ยวกับ~
~
ระบุ POSIX ~
ไม่ได้อยู่ใน Thomson หรือ Bourne shell (ซึ่งในเวลานั้นมีให้ในรูป/bin/sh
) มันไม่ได้อยู่ในrc
หรืออนุพันธ์ (ที่จะใช้อย่างอื่น)
bash
หากHOME
ไม่ได้ตั้งค่า~
จะขยายไปยังโฮมไดเร็กทอรีของผู้ใช้จากฐานข้อมูล passwd เพื่อให้เป็นกรณีที่ไม่อาจขยายไปยังค่าของ~
$HOME
bash
ก่อนที่ bash4 จะใช้ในการทำการวนรอบตามการขยายตัวของตัวหนอน (ลองHOME='/*' bash -c 'echo /*'
) ดังนั้นHOME=/*; [ "$HOME" = ~ ]
จะกลับข้อผิดพลาดที่นั่น
get_current_user_info
ซึ่งใช้getpwuid
บนแพลตฟอร์มทั้งหมด แต่ Tandem
~
จะเทียบเท่ากับ$HOME
ในสภาพแวดล้อม POSIX ใด ๆ ; แต่ฉันอาจจะผิด