Mengapa saya tidak bisa menggunakan '~' alih-alih '/ home / nama pengguna /' saat memberikan path file

43

Saya bisa menggunakan ~alih-alih /home/username/menunjuk ke jalur file ketika, misalnya, membuka ritsleting .zipfile.

Namun, hari ini ketika saya mengikuti cara yang sama untuk menjalankan contoh RNN di terminal, tensorflow.python.framework.errors_impl.NotFoundErrorterlempar.

$ python ptb_word_lm.py --data_path=~/anaconda2/lib/python2.7/site-packages/tensorflow/models-master/tutorials/rnn/simple-examples/data/ --model=small 
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcublas.so.8.0 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcudnn.so.5 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcufft.so.8.0 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcurand.so.8.0 locally
Traceback (most recent call last):
  File "ptb_word_lm.py", line 374, in <module>
    tf.app.run()
  File "/home/hok/anaconda2/lib/python2.7/site-packages/tensorflow/python/platform/app.py", line 44, in run
    _sys.exit(main(_sys.argv[:1] + flags_passthrough))
  File "ptb_word_lm.py", line 321, in main
    raw_data = reader.ptb_raw_data(FLAGS.data_path)
  File "/home/hok/anaconda2/lib/python2.7/site-packages/tensorflow/models-master/tutorials/rnn/ptb/reader.py", line 73, in ptb_raw_data
    word_to_id = _build_vocab(train_path)
  File "/home/hok/anaconda2/lib/python2.7/site-packages/tensorflow/models-master/tutorials/rnn/ptb/reader.py", line 34, in _build_vocab
    data = _read_words(filename)
  File "/home/hok/anaconda2/lib/python2.7/site-packages/tensorflow/models-master/tutorials/rnn/ptb/reader.py", line 30, in _read_words
    return f.read().decode("utf-8").replace("\n", "<eos>").split()
  File "/home/hok/anaconda2/lib/python2.7/site-packages/tensorflow/python/lib/io/file_io.py", line 106, in read
    self._preread_check()
  File "/home/hok/anaconda2/lib/python2.7/site-packages/tensorflow/python/lib/io/file_io.py", line 73, in _preread_check
    compat.as_bytes(self.__name), 1024 * 512, status)
  File "/home/hok/anaconda2/lib/python2.7/contextlib.py", line 24, in __exit__
    self.gen.next()
  File "/home/hok/anaconda2/lib/python2.7/site-packages/tensorflow/python/framework/errors_impl.py", line 469, in raise_exception_on_not_ok_status
    pywrap_tensorflow.TF_GetCode(status))
tensorflow.python.framework.errors_impl.NotFoundError: ~/anaconda2/lib/python2.7/site-packages/tensorflow/models-master/tutorials/rnn/simple-examples/data/ptb.train.txt

Lalu saya ganti ~dengan /home/username/, dan itu berfungsi dengan baik.

Mengapa saya tidak bisa menggunakan ~alih-alih /home/username/menunjuk ke jalur file ketika menjalankan contoh RNN?

Bisakah Anda memberi tahu saya secara detail?

JNing
sumber
@OskarSkog Bukankah seharusnya shell memperluas ~sebelum argumen dilewatkan ke python? Sama seperti shell akan memperluas backslash lolos di jalan, atau menghapus tanda kutip jika jalan itu dikutip.
Micheal Johnson
1
Tidak seperti itu $VARIABLES, ~hanya diperluas pada awal string.
alexis
@OskarSkog, "Python tidak tahu apa ~ berarti" menyiratkan bahwa masalah khusus untuk Python kurang sepotong fungsionalitas, mendirikan sebuah harapan yang tidak masuk akal bahwa fungsi tersebut (melakukan ekspansi setelah menjadi exec'd) harus tersedia secara luas di alat UNIX .
Charles Duffy

Jawaban:

45

Anda perlu memahami bahwa ~biasanya diperluas oleh shell; program yang Anda panggil tidak pernah melihatnya, mereka melihat nama path lengkap seperti yang dimasukkan oleh bash. Tapi ini hanya terjadi ketika tilde berada di awal argumen (dan tidak dikutip).

Jika program Python yang Anda jalankan menggunakan modul yang ingin getoptmem-parsing commandline-nya, Anda bisa memberikan argumen --data-pathopsi sebagai "kata" terpisah untuk memungkinkan ekspansi tilde:

$ python ptb_word_lm.py --data_path ~/anaconda2/lib/python2.7/...

Dalam kode Anda sendiri, Anda dapat menggunakan getoptatau argparseuntuk pemrosesan argumen, dan juga bisa secara manual memperluas tildes seperti yang disarankan oleh jawaban @ JacobVlijm.

PS. Tilde juga diperluas pada awal ekspresi penugasan variabel shell seperti DIRNAME=~/anaconda2; meskipun tilde dalam pertanyaan Anda juga mengikuti tanda sama dengan, penggunaan ini tidak memiliki arti khusus untuk shell (itu hanya sesuatu yang diteruskan ke program) dan tidak memicu ekspansi.

Alexis
sumber
6
Kecuali Anda sudah tahu getopt , gunakan argparsejika Anda sedang menulis Python.
Nick T
Saya telah menambahkan argparsejawaban karena itu adalah alternatif utama, tetapi secara pribadi saya merasa lebih sulit untuk digunakan daripada getopt, tidak mudah. YMMV.
alexis
33

Ekspansi Tilde dalam python

Jawabannya singkat & sederhana:

python tidak berkembang ~kecuali jika Anda menggunakan:

import os
os.path.expanduser('~/your_directory')

Lihat juga di sini :

os.path.expanduser (path)
Pada Unix dan Windows, kembalikan argumen dengan komponen awal pengguna ~ atau ~ digantikan oleh direktori home pengguna tersebut.

Pada Unix, inisial ~ digantikan oleh variabel lingkungan HOME jika disetel; jika tidak, direktori home pengguna saat ini dicari di direktori kata sandi melalui modul built-in pwd. Pengguna awal ~ dilihat langsung di direktori kata sandi.

Yakub Vlijm
sumber
11
Secara umum, Anda tidak boleh berasumsi bahwa ekspansi tilde dilakukan pada level OS, itu adalah sesuatu yang dilakukan unix shell (dan tidak semuanya!) Lakukan untuk Anda.
farsil
1
Saya pikir masalah yang lebih relevan dijabarkan dalam jawaban alexis: posisi ~dalam daftar argumen shell.
David Foerster
@ Farsil, saya tidak setuju. Program dapat dibuat portabel, tetapi ketika Anda menjalankannya dari baris perintah, Anda melakukannya pada sistem tertentu. Dan jangan lupa bahwa ini adalah askubuntu.com, dan Ubuntu selalu Unix ( sejauh yang kami tahu :-)
alexis
1
@alexis: Ubuntu juga tidak melakukan ekspansi pada level OS. Masih fungsionalitas shell.
user2357112 mendukung Monica
1
Methinks Anda membelah rambut. Tidak ada yang mengatakan kernel melakukannya. Intinya, itu tidak dilakukan oleh program yang mengambil argumen.
alexis
12

Perluasan Tilde hanya dilakukan dalam beberapa konteks yang sedikit berbeda antar shell .

Sementara itu dilakukan di:

var=~

Atau

export var=~

di beberapa kerang. Itu tidak ada

echo var=~
env var=~ cmd
./configure --prefix=~

dalam kulit POSIX.

Hal ini dalam bashmeskipun ketika tidak dalam modus kesesuaian POSIX (seperti ketika disebut sebagai sh, atau ketika POSIXLY_CORRECTberada di lingkungan):

$ bash -c 'echo a=~'
a=/home/stephane
$ POSIXLY_CORRECT= bash -c 'echo a=~'
a=~
$ SHELLOPTS=posix bash -c 'echo a=~'
a=~
$ (exec -a sh bash -c 'echo a=~')
a=~

Namun itu hanya ketika apa yang ada di sebelah kiri =berbentuk seperti nama variabel valid yang tidak dikutip , jadi sementara itu akan diperluas cmd prefix=~, itu tidak akan menjadi cmd --prefix=~(karena --prefixbukan nama variabel yang valid) atau di cmd "p"refix=~(karena yang dikutip p) atau di var=prefix; cmd $var=~.

Di zsh, Anda dapat mengatur magic_equal_substopsi untuk ~diperluas setelah tanda kutip =.

$ zsh -c 'echo a=~'
a=~
$ zsh -o magic_equal_subst -c 'echo a=~'
a=/home/stephane
$ zsh -o magic_equal_subst -c 'echo --a=~'
--a=/home/stephane

Dalam hal ~(sebagai lawan dari ~user), Anda bisa menggunakan $HOMEsaja:

cmd --whatever="$HOME/whatever"

~memperluas ke nilai $HOME. Jika $HOMEtidak disetel, perilaku bervariasi antar shell. Beberapa shell meminta database pengguna. Jika Anda ingin memperhitungkannya, Anda dapat melakukannya (dan itulah yang harus Anda lakukan untuk ~user):

dir=~ # or dir=~user
cmd --whatever="$dir/whatever"

Bagaimanapun, dalam cangkang selain zshingat Anda perlu mengutip ekspansi variabel!

Stéphane Chazelas
sumber
1
Manual referensi Bash tampaknya mengatakan bahwa tilde hanya diperluas pada penugasan variabel dan pada awal kata, jadi memperluasnya echo a=~tampaknya bertentangan dengan manual.
ilkkachu
@ilkkachu, ya manualnya tidak lengkap. Ini juga tidak menentukan secara jelas dalam konteks apa yang ~akan diperluas (apa yang dimaksud dengan "kata"). Lihat tautan di bagian atas jawaban untuk perincian lebih lanjut.
Stéphane Chazelas
6

~memiliki aturan ekspansi tertentu, yang tidak dipenuhi perintah Anda. Secara khusus, itu diperluas hanya ketika tanda kutip, baik di awal kata (misalnya python ~/script.py) atau di awal penugasan variabel (misalnya PYTHONPATH=~/scripts python script.py). Apa yang Anda miliki adalah --data_path=~/blablasatu kata dalam istilah shell, jadi ekspansi tidak dilakukan.

Perbaikan segera adalah dengan menggunakan $HOMEvariabel shell, yang mengikuti aturan ekspansi variabel reguler:

python ptb_word_lm.py --data_path=$HOME/blabla
Dmitry Grigoryev
sumber
Itu agak terlalu disederhanakan, ada konteks lain di mana ekspansi dilakukan seperti di PATH=$PATH:~/bin. Juga yang $HOMEperlu dikutip atau dibelah + glob berlaku di shell selain zsh.
Stéphane Chazelas
@sch maaf, tetapi tautan yang Anda berikan di komentar di sana mengarah ke pertanyaan tentang mouse optik, tanpa menyebutkan ekspansi tilde. Bisakah Anda jelaskan itu?
Sergiy Kolodyazhnyy
Jawaban yang bagus. Ini pada dasarnya meringkas apa yang bashdinyatakan secara manual di Tilde Expansionbagian ini. +1
Sergiy Kolodyazhnyy
Maaf, saya sudah terbiasa menggunakan tautan intra-situs di unix.SE karena [link](/a/146697)saya tidak menyadari kami berada di situs yang berbeda di sini.
Tautannya