Có phải ~ luôn luôn bằng $ HOME


40

Tôi biết điều này có thể đã được hỏi trước đây, nhưng tôi không thể tìm thấy nó với Google.

Được

  • Nền tảng Linux
  • Không có cấu hình thay đổi $ HOME
  • bash

Sẽ ~ == $HOMElà sự thật?


3
Tôi tin là như vậy, nhưng đây không phải là vấn đề cụ thể của Linux. Thay vào đó, tôi tin rằng ~sẽ tương đương với $HOMEtrong bất kỳ môi trường POSIX nào; nhưng tôi có thể sai
HalosGhost

4
Mặc dù câu trả lời dưới đây không phải lúc nào. So sánh echo "~"echo "$HOME".
Sparhawk

@Sparhawk Chờ đã, vậy 1 + 1 không phải là 2? Đó là một âm mưu! Chính phủ đang che giấu điều gì đó từ chúng tôi! : P
Doorknob

1
@Sparhawk, bạn sẽ nhận thấy OP thực sự không trích dẫn ~hoặc $HOME. : P
HalosGhost

2
@HalosGhost À, điểm tốt. (Ngoài ra, sau đó tôi nhận thấy rằng câu trả lời của Michael Homer đề cập đến "một người không được trích dẫn ~".) Dù sao, một điều cần lưu ý cho người đọc bình thường, như tôi.
Sparhawk

Câu trả lời:


46

Điều quan trọng cần hiểu là ~mở rộng là một tính năng của shell (của một số shell), nó không phải là một nhân vật kỳ diệu hơn có nghĩa là thư mục nhà của bạn bất cứ nơi nào nó được sử dụng.

Nó được mở rộng (bởi shell, là một ứng dụng được sử dụng để giải thích các dòng lệnh), giống như $varđược mở rộng thành giá trị của nó trong một số điều kiện khi được sử dụng trong một dòng lệnh shell trước khi lệnh được thực thi.

Tính năng đó lần đầu tiên xuất hiện trong vỏ C vào cuối những năm 1970 (vỏ Bourne không có nó, cũng không phải là vỏ trước của nó), sau đó được thêm vào vỏ Korn (vỏ mới hơn được chế tạo trên vỏ Bourne trong vỏ Những năm 80). Cuối cùng, nó đã được chuẩn hóa bởi POSIX và hiện có sẵn trong hầu hết các shell bao gồm cả những cái không phải POSIX như fish.

Bởi vì nó được sử dụng rộng rãi như vậy trong shell, một số ứng dụng không shell cũng nhận ra nó có nghĩa là thư mục chính. Đó là trường hợp của nhiều ứng dụng trong các tập tin cấu hình của họ hoặc họ riêng dòng lệnh ( mutt, slrn, vim...).

bashcụ thể (là vỏ của dự án GNU và được sử dụng rộng rãi trong nhiều hệ điều hành dựa trên Linux), khi được gọi là sh, chủ yếu tuân theo các quy tắc POSIX về ~mở rộng và trong các khu vực không được chỉ định bởi POSIX, hoạt động chủ yếu như vỏ Korn (của mà nó là một bản sao một phần).

Mặc dù $varđược mở rộng ở hầu hết các nơi (ngoại trừ bên trong các trích dẫn đơn), ~việc mở rộng, suy nghĩ lại chỉ được mở rộng trong một vài điều kiện cụ thể.

Nó được mở rộng khi trên đối số của chính nó trong bối cảnh danh sách, trong bối cảnh nơi một chuỗi được mong đợi.

Dưới đây là một vài ví dụ về nơi nó được mở rộng tại bash:

  • cmd arg ~ other arg
  • var=~
  • var=x:~:x(được POSIX yêu cầu, được sử dụng cho các biến như PATH, MANPATH...)
  • for i in ~
  • [[ ~ = text ]]
  • [[ text = ~ ]](việc mở rộng ~được lấy làm mẫu trong AT & T kshnhưng không bashkể từ 4.0).
  • case ~ in ~) ...
  • ${var#~} (mặc dù không có trong một số vỏ khác)
  • cmd foo=~(mặc dù không phải khi được gọi là shvà chỉ khi những gì ở bên trái của =nó có hình dạng như một bashtên biến không được trích dẫn )
  • cmd ~/x (rõ ràng là yêu cầu của POSIX)
  • cmd ~:x(nhưng không x:~:xhoặc x-~-x)
  • a[~]=foo; echo "${a[~]} $((a[~]))" (không phải trong một số vỏ khác)

Dưới đây là một vài ví dụ mà nó không được mở rộng:

  • echo "~" '~'
  • echo ~@ ~~(cũng lưu ý rằng ~ucó nghĩa là mở rộng sang thư mục chính của người dùng u).
  • echo @~
  • (( HOME == ~ )), $(( var + ~ ))
  • với extglob: case $var in @(~|other))...(mặc dù case $var in ~|other)vẫn ổn).
  • ./configure --prefix=~(như --prefixkhông phải là một tên biến hợp lệ)
  • cmd "foo"=~(trong bash, vì các trích dẫn).
  • khi được gọi là sh: export "foo"=~, env JAVA_HOME=~ cmd...

Đối với những gì nó mở rộng thành: ~một mình mở rộng đến nội dung của HOMEbiến hoặc khi nó không được đặt, vào thư mục chính của người dùng hiện tại trong cơ sở dữ liệu tài khoản (như một phần mở rộng vì POSIX không xác định hành vi đó).

Cần lưu ý rằng trong ksh88 và bashcác phiên bản trước 4.0, việc mở rộng dấu ngã đã trải qua quá trình toàn cầu hóa (tạo tên tệp) trong bối cảnh danh sách:

$ bash -c 'echo "$HOME"'
/home/***stephane***
$ bash -c 'echo ~'
/home/***stephane*** /home/stephane
$ bash -c 'echo "~"'
~

Đó không phải là một vấn đề trong các trường hợp thông thường.

Lưu ý rằng vì nó được mở rộng, cảnh báo tương tự được áp dụng như các hình thức mở rộng khác.

cd ~

Không hoạt động nếu $HOMEbắt đầu với -hoặc chứa ..các thành phần. Vì vậy, mặc dù rất khó có thể tạo ra bất kỳ sự khác biệt nào, nhưng nói đúng ra, người ta nên viết:

cd -P -- ~

Hoặc thậm chí:

case ~ in
  (/*) cd -P ~;;
  (*) d=~; cd -P "./$d";;
esac

(để bao gồm các giá trị $HOMEnhư -, +2...) hoặc đơn giản là:

cd

(như cdđưa bạn đến thư mục nhà của bạn mà không có bất kỳ đối số)

Các vỏ khác có bản ~mở rộng tiên tiến hơn . Chẳng hạn, trong zsh, chúng ta có:

  • ~4, ~-, ~-2(Với hoàn) được sử dụng để mở rộng thư mục trong đống thư mục của bạn (những nơi bạn đã cdđến trước đó).
  • thư mục có tên động . Bạn có thể xác định cơ chế của riêng mình để quyết định cách ~somethingmở rộng.

25

Trong bất kỳ phiên bản Bash nào trên bất kỳ hệ thống nào, vâng . ~như một thuật ngữ riêng được định nghĩa để mở rộng thành:

Giá trị của $ HOME

vì vậy nó sẽ luôn giống như bất cứ thứ gì $HOMEvới lớp vỏ hiện tại. Có một số bản mở rộng dấu ngã khác, chẳng hạn như ~userđối với userthư mục chính của nó, nhưng một bản không được trích dẫn ~riêng sẽ luôn mở rộng sang "$HOME".

Lưu ý rằng hành vi của ~$HOMEcó thể khác nhau trong một số trường hợp: cụ thể, nếu $HOMEchứa khoảng trắng (hoặc các ký tự IFS khác ), thì $HOME(không trích dẫn) sẽ mở rộng thành nhiều từ, trong khi ~luôn luôn là một từ. ~mở rộng tương đương với "$HOME"(trích dẫn).

Liên quan đến câu hỏi cụ thể của bạn:

[[ $HOME == ~ ]]

luôn luôn đúng, bởi vì [[ ngăn chặn việc tách từ. [[ ~ == $HOME ]có thể không nếu HOMEcó các ký tự khớp mẫu trong đó, nhưng [[ ~ == "$HOME" ]](nghĩa là được trích dẫn "$HOME") luôn luôn đúng. Sử dụng nó trong dấu ngoặc đơn có thể là một lỗi cú pháp cho các giá trị HOMEchứa khoảng trắng hoặc ký tự đặc biệt. Đối với bất kỳ cấu hình thư mục nhà hợp lý ~"$HOME"đều giống nhau và so sánh như nhau.


Stéphane Chazelas đã lưu ý một trường hợp trong các bình luận trong đó ~$HOMEđưa ra các giá trị khác nhau: nếu bạn unset HOME, khi bạn sử dụng ~Bash sẽ gọi getpwuidđể đọc một giá trị từ cơ sở dữ liệu mật khẩu. Trường hợp này được loại trừ bởi tình trạng của bạn không có thay đổi cấu hình $HOME, nhưng tôi sẽ đề cập đến nó ở đây cho đầy đủ.


1
Tuy nhiên, /bin/shcó thể không bash. Tôi không chắc rằng shthông số kỹ thuật của Posix nói về~
Basile Starynkevitch

1
POSIX chỉ định ~. ~không có trong vỏ Thomson hoặc Bourne (thời đó có sẵn như /bin/sh). Nó không ở trong rchoặc dẫn xuất của nó (nơi nó được sử dụng cho mục đích khác)
Stéphane Chazelas

5
Trong một vài shell bao gồm bash, nếu HOMEkhông được đặt, ~sẽ mở rộng đến thư mục chính của người dùng từ cơ sở dữ liệu passwd. Vì vậy, đó là một trường hợp ~có thể không mở rộng đến giá trị của $HOME.
Stéphane Chazelas

1
Lưu ý rằng bashtrước khi bash4 được sử dụng để thực hiện Globing khi mở rộng dấu ngã (thử HOME='/*' bash -c 'echo /*'). Vì vậy, HOME=/*; [ "$HOME" = ~ ]sẽ trả lại một lỗi ở đó.
Stéphane Chazelas

4
@cuonglm Mình đã kiểm tra mã nguồn. Nó rốt cuộc gọi get_current_user_info , trong đó sử dụng getpwuidtrên tất cả các nền tảng nhưng Tandem .
Michael Homer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.