Apakah ~ selalu sama dengan $ HOME

40

Saya tahu ini mungkin telah ditanyakan sebelumnya, tetapi saya tidak dapat menemukannya dengan Google.

Diberikan

  • Kernel Linux
  • Tidak ada konfigurasi yang mengubah $ HOME
  • pesta

Apakah ini ~ == $HOMEbenar?

PythonNut
sumber
3
Saya percaya begitu, tapi ini bukan masalah khusus Linux. Sebaliknya, saya percaya ~akan setara dengan $HOMElingkungan POSIX apa pun; tapi saya bisa saja salah.
HalosGhost
4
Meskipun ada jawaban di bawah ini ... tidak selalu. Bandingkan echo "~"dan echo "$HOME".
Sparhawk
@Sparhawk Tunggu, jadi 1 +1 bukan 2? Ini konspirasi! Pemerintah menyembunyikan sesuatu dari kita! : P
Doorknob
1
@Sparhawk, Anda akan melihat OP sebenarnya tidak mengutip ~atau $HOME. : P
HalosGhost
2
@HalosGhost Ah, poin bagus. (Juga, saya kemudian memperhatikan bahwa jawaban Michael Homer menyebutkan "satu tanda kutip ~".) Bagaimanapun, sesuatu yang perlu diingat oleh pembaca biasa, seperti saya.
Sparhawk

Jawaban:

46

Yang penting untuk dipahami adalah bahwa ~ekspansi adalah fitur dari shell (dari beberapa shell), itu bukan karakter ajaib daripada berarti direktori home Anda di mana pun ia digunakan.

Itu diperluas (oleh shell, yang merupakan aplikasi yang digunakan untuk menafsirkan baris perintah), seperti $vardiperluas ke nilainya dalam beberapa kondisi ketika digunakan dalam baris perintah shell sebelum perintah dieksekusi.

Fitur itu pertama kali muncul di c-shell pada akhir 1970-an (cangkang Bourne tidak memilikinya, pendahulunya juga cangkang Thompson), kemudian ditambahkan ke cangkang Korn (cangkang yang lebih baru dibangun di atas cangkang Bourne di 80-an). Itu akhirnya distandarisasi oleh POSIX dan sekarang tersedia di sebagian besar shell termasuk yang non-POSIX seperti fish.

Karena itu digunakan secara luas dalam shell, beberapa aplikasi non-shell juga mengenalinya sebagai direktori home. Itulah kasus banyak aplikasi dalam file konfigurasi atau mereka sendiri baris perintah ( mutt, slrn, vim...).

bashkhusus (yang merupakan shell dari proyek GNU dan banyak digunakan di banyak sistem operasi berbasis Linux), ketika dipanggil sebagai sh, sebagian besar mengikuti aturan POSIX tentang ~ekspansi, dan di daerah yang tidak ditentukan oleh POSIX, berperilaku seperti shell Korn (dari yang merupakan bagian klon).

Sementara $vardiperluas di sebagian besar tempat (kecuali di dalam tanda kutip tunggal), ~ekspansi, menjadi renungan hanya diperluas dalam beberapa kondisi tertentu.

Ini diperluas ketika pada argumennya sendiri dalam konteks daftar, dalam konteks di mana string diharapkan.

Berikut adalah beberapa contoh perluasannya bash:

  • cmd arg ~ other arg
  • var=~
  • var=x:~:x(diperlukan oleh POSIX, digunakan untuk variabel seperti PATH, MANPATH...)
  • for i in ~
  • [[ ~ = text ]]
  • [[ text = ~ ]](perluasan ~diambil sebagai pola AT&T kshtetapi tidak bashsejak 4.0).
  • case ~ in ~) ...
  • ${var#~} (meskipun tidak di beberapa kerang lain)
  • cmd foo=~(meskipun tidak ketika dipanggil sebagai sh, dan hanya ketika apa yang ada di sebelah kiri =berbentuk seperti bashnama variabel yang tidak dikutip )
  • cmd ~/x (diperlukan oleh POSIX jelas)
  • cmd ~:x(tapi tidak x:~:xatau x-~-x)
  • a[~]=foo; echo "${a[~]} $((a[~]))" (tidak di beberapa kerang lain)

Berikut adalah beberapa contoh di mana itu tidak diperluas:

  • echo "~" '~'
  • echo ~@ ~~(juga perhatikan bahwa ~uini dimaksudkan untuk memperluas ke direktori home pengguna u).
  • echo @~
  • (( HOME == ~ )), $(( var + ~ ))
  • dengan extglob: case $var in @(~|other))...(meskipun case $var in ~|other)tidak masalah).
  • ./configure --prefix=~(karena --prefixbukan nama variabel yang valid)
  • cmd "foo"=~(dalam bash, karena tanda kutip).
  • ketika dipanggil sebagai sh: export "foo"=~, env JAVA_HOME=~ cmd...

Mengenai apa yang diperluas ke: ~sendiri diperluas ke konten HOMEvariabel, atau ketika tidak disetel, ke direktori home dari pengguna saat ini dalam basis data akun (sebagai ekstensi karena POSIX membiarkan perilaku tidak terdefinisi).

Perlu dicatat bahwa dalam ksh88 dan bashversi sebelum 4.0, ekspansi tilde mengalami globbing (pembuatan nama file) dalam konteks daftar:

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

Itu seharusnya tidak menjadi masalah dalam kasus-kasus biasa.

Perhatikan bahwa karena diperluas, peringatan yang sama berlaku sebagai bentuk ekspansi lainnya.

cd ~

Tidak berfungsi jika $HOMEdimulai dengan -atau mengandung ..komponen. Jadi, meskipun sangat kecil kemungkinannya untuk membuat perbedaan, secara tegas, kita harus menulis:

cd -P -- ~

Atau bahkan:

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

(untuk menutupi nilai $HOMElike -, +2...) atau hanya:

cd

(seperti cdmembawa Anda ke direktori home Anda tanpa argumen)

Kerang lainnya memiliki ~ekspansi yang lebih maju . Misalnya, di zsh, kami memiliki:

  • ~4, ~-, ~-2(Dengan penyelesaian) yang digunakan untuk memperluas direktori dalam direktori stack Anda (tempat Anda sudah cdsebelum).
  • direktori bernama dinamis . Anda dapat menentukan mekanisme Anda sendiri untuk memutuskan bagaimana ~somethingdiperluas.
Stéphane Chazelas
sumber
25

Dalam semua versi Bash di sistem apa pun, ya . ~sebagai istilah sendiri didefinisikan untuk diperluas ke:

Nilai $ HOME

jadi itu akan selalu sama dengan apa pun yang $HOMEada pada shell saat ini. Ada beberapa ekspansi tilde lainnya, seperti ~useruntuk userdirektori home, tetapi satu tanda kutip ~sendiri akan selalu diperluas ke "$HOME".

Perhatikan bahwa perilaku dari ~dan $HOMEdapat berbeda dalam beberapa kasus: pada khususnya, jika $HOMEmengandung spasi (atau lainnya IFS karakter), maka $HOME(kuotasi) akan diperluas untuk beberapa kata, sementara ~selalu satu kata. ~memperluas ekuivalen untuk "$HOME"(dikutip).

Sehubungan dengan pertanyaan spesifik Anda:

[[ $HOME == ~ ]]

selalu benar, karena [[ menekan pemisahan kata. [[ ~ == $HOME ]mungkin tidak jika HOMEmemiliki karakter yang cocok dengan pola di dalamnya, tetapi [[ ~ == "$HOME" ]](yaitu, dikutip "$HOME") selalu benar. Menggunakannya di dalam tanda kurung tunggal dapat menjadi kesalahan sintaksis untuk nilai yang HOMEberisi spasi atau karakter khusus. Untuk konfigurasi direktori home yang masuk akal ~dan "$HOME"sama dan bandingkan sebagai sama.


Stéphane Chazelas telah mencatat sebuah kasus di komentar di mana ~dan $HOMEmemberikan nilai yang berbeda: jika Anda unset HOME, maka ketika Anda menggunakan ~Bash akan menelepon getpwuiduntuk membaca nilai dari basis data kata sandi. Kasing ini dikecualikan oleh kondisi Anda yang tidak memiliki konfigurasi berubah $HOME, tetapi saya akan menyebutkannya di sini untuk kelengkapan.

Michael Homer
sumber
1
Namun, /bin/shmungkin tidak bash. Saya tidak yakin bahwa shspesifikasi Posix bercerita tentang~
Basile Starynkevitch
1
POSIX menentukan ~. ~tidak ada dalam cangkang Thomson atau Bourne (yang pada waktunya tersedia sebagai /bin/sh). Itu bukan dalam rcatau turunannya (di mana ia digunakan untuk sesuatu yang lain)
Stéphane Chazelas
5
Dalam beberapa shell termasuk bash, jika HOMEtidak disetel, ~memperluas ke direktori home pengguna dari database passwd. Jadi itu adalah kasus di mana ~mungkin tidak berkembang ke nilai $HOME.
Stéphane Chazelas
1
Perhatikan bahwa bashsebelum bash4 digunakan untuk melakukan globbing pada ekspansi tilde (coba HOME='/*' bash -c 'echo /*'). Jadi HOME=/*; [ "$HOME" = ~ ]akan mengembalikan kesalahan di sana.
Stéphane Chazelas
4
@cuonglm Saya memeriksa kode sumber. Ini akhirnya panggilan get_current_user_info , yang menggunakan getpwuidpada semua platform tapi Tandem .
Michael Homer