Tại sao tôi không thể sử dụng '~' thay vì '/ home / tên người dùng /' khi đưa đường dẫn tệp


43

Tôi có thể sử dụng ~thay vì /home/username/trỏ đến đường dẫn tệp khi, ví dụ, giải nén .ziptệp.

Tuy nhiên, hôm nay khi tôi theo cùng một cách để chạy một ví dụ RNN trong thiết bị đầu cuối, tensorflow.python.framework.errors_impl.NotFoundErrorđã bị ném.

$ 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

Sau đó, tôi thay thế ~bằng /home/username/, và nó hoạt động đúng.

Tại sao tôi không thể sử dụng ~thay vì /home/username/trỏ đến đường dẫn tệp khi chạy ví dụ RNN?

Bạn có thể cho tôi biết chi tiết?




@OskarSkog Không nên mở rộng trình bao ~trước khi đối số được truyền cho python? Giống như shell sẽ mở rộng dấu gạch chéo ngược thoát trong đường dẫn hoặc xóa dấu ngoặc kép nếu đường dẫn được trích dẫn.
Micheal Johnson

1
Không giống như $VARIABLES, ~chỉ được mở rộng ở đầu chuỗi.
alexis

@OskarSkog, "Python không biết ~ nghĩa là gì" ngụ ý rằng một vấn đề cụ thể đối với Python thiếu một phần chức năng, thiết lập một kỳ vọng vô lý rằng chức năng đó (thực hiện mở rộng sau khi được exec'd) nên có sẵn rộng rãi trong các công cụ UNIX .
Charles Duffy

Câu trả lời:


45

Bạn cần hiểu rằng ~thường được mở rộng bởi vỏ; các chương trình bạn gọi không bao giờ thấy nó, họ thấy tên đường dẫn đầy đủ được chèn bởi bash. Nhưng điều này chỉ xảy ra khi dấu ngã ở đầu một đối số (và không được trích dẫn).

Nếu chương trình Python bạn đang chạy sử dụng một mô-đun như getoptphân tích dòng lệnh của nó, bạn có thể đưa ra đối số của --data-pathtùy chọn dưới dạng một "từ" riêng biệt để cho phép mở rộng dấu ngã:

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

Trong mã của riêng bạn, bạn có thể sử dụng getopthoặc argparseđể xử lý đối số và cũng có thể mở rộng các dấu ngã theo cách thủ công như câu trả lời của @ JacobVlijm.

Tái bút Dấu ngã cũng được mở rộng khi bắt đầu biểu thức gán biến shell như DIRNAME=~/anaconda2; mặc dù dấu ngã trong câu hỏi của bạn cũng tuân theo dấu bằng, nhưng cách sử dụng này không có ý nghĩa đặc biệt đối với vỏ (nó chỉ là thứ được truyền cho chương trình) và không kích hoạt mở rộng.


6
Trừ khi bạn đã biết getopt , hãy sử dụng argparsenếu bạn đang viết Python.
Nick T

Tôi đã thêm vào argparsecâu trả lời vì đây là lựa chọn chính, nhưng cá nhân tôi thấy nó khó sử dụng hơn nhiều getopt, không dễ hơn. YMMV.
alexis

33

Mở rộng Tilde trong python

Câu trả lời ngắn gọn & đơn giản:

python không mở rộng ~trừ khi bạn sử dụng:

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

Xem thêm tại đây :

os.path.Exanduser (đường dẫn)
Trên Unix và Windows, trả về đối số có thành phần ban đầu là ~ hoặc ~ người dùng được thay thế bởi thư mục chính của người dùng đó.

Trên Unix, một ~ ban đầu được thay thế bằng biến môi trường HOME nếu nó được đặt; mặt khác, thư mục chính của người dùng hiện tại được tra cứu trong thư mục mật khẩu thông qua mô-đun pwd tích hợp. Một người dùng ban đầu ~ được tra cứu trực tiếp trong thư mục mật khẩu.


11
Nói chung, bạn không bao giờ nên cho rằng việc mở rộng dấu ngã được thực hiện ở cấp độ HĐH, đó là điều mà unix shell (và không phải tất cả trong số chúng!) Làm cho bạn.
farsil

1
Tôi nghĩ rằng vấn đề có liên quan hơn được nêu ra trong câu trả lời của alexis: vị trí của ~trong danh sách đối số shell.
David foerster

@farsil, tôi không đồng ý. Các chương trình có thể được thực hiện di động, nhưng khi bạn chạy chúng từ dòng lệnh, bạn làm như vậy trên một hệ thống cụ thể. Và đừng quên rằng đây là Askubfox.com và Ubuntu luôn là Unix ( theo như chúng ta biết :-)
alexis

1
@alexis: Ubuntu cũng không mở rộng dấu ngã ở cấp hệ điều hành. Đó vẫn là chức năng shell.
dùng2357112

1
Methinks bạn đang chia tóc. Không ai nói kernel đang làm điều đó. Vấn đề là, nó không được thực hiện bởi chương trình lấy các đối số.
alexis

12

Mở rộng Tilde chỉ được thực hiện trong một vài bối cảnh thay đổi đôi chút giữa các lớp vỏ .

Trong khi nó được thực hiện trong:

var=~

Hoặc là

export var=~

trong một số vỏ. Nó không ở trong

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

trong vỏ POSIX.

Đó là trong bashmặc dù khi không ở chế độ phù hợp POSIX (như khi gọi là sh, hoặc khi POSIXLY_CORRECTđang ở trong môi trường):

$ 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=~

Tuy nhiên, đó chỉ là khi những gì ở bên trái của =nó có hình dạng như một tên biến hợp lệ không được trích dẫn, vì vậy trong khi nó sẽ được mở rộng cmd prefix=~, nó sẽ không nằm trong cmd --prefix=~(vì --prefixkhông phải là một tên biến hợp lệ) cũng không phải cmd "p"refix=~(vì được trích dẫn p) cũng như trong var=prefix; cmd $var=~.

Trong zsh, bạn có thể đặt magic_equal_substtùy chọn ~để được mở rộng sau khi không được trích dẫn =.

$ 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

Trong trường hợp ~(trái ngược với ~user), bạn chỉ có thể sử dụng $HOMEthay thế:

cmd --whatever="$HOME/whatever"

~mở rộng đến giá trị của $HOME. Nếu $HOMEkhông được đặt, hành vi khác nhau giữa các shell. Một số shell truy vấn cơ sở dữ liệu người dùng. Nếu bạn muốn tính đến điều đó, bạn có thể làm (và đó cũng là điều bạn sẽ phải làm ~user):

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

Trong mọi trường hợp, trong shell khác hơn là zshnhớ bạn cần trích dẫn mở rộng biến!


1
Hướng dẫn tham khảo của Bash dường như nói rằng các dấu ngã chỉ được mở rộng trên các phép gán biến đổi và khi bắt đầu một từ, vì vậy việc mở rộng nó echo a=~dường như mâu thuẫn với hướng dẫn sử dụng.
ilkkachu

@ilkkachu, vâng hướng dẫn không đầy đủ. Nó cũng không xác định rõ ràng trong bối cảnh nào ~sẽ được mở rộng (nghĩa của "từ"). Xem liên kết ở đầu câu trả lời để biết thêm chi tiết.
Stéphane Chazelas

6

~có các quy tắc mở rộng cụ thể, mà lệnh của bạn không thỏa mãn. Cụ thể, nó chỉ được mở rộng khi không được trích dẫn, ở đầu một từ (ví dụ python ~/script.py) hoặc ở đầu một phép gán biến (ví dụ PYTHONPATH=~/scripts python script.py). Những gì bạn có là --data_path=~/blablamột từ duy nhất trong thuật ngữ shell, vì vậy việc mở rộng không được thực hiện.

Một sửa chữa ngay lập tức là sử dụng $HOMEbiến shell, tuân theo các quy tắc mở rộng biến thông thường:

python ptb_word_lm.py --data_path=$HOME/blabla

Đó là một chút quá mức, có những bối cảnh khác là mở rộng dấu ngã được thực hiện như trong PATH=$PATH:~/bin. Ngoài ra, $HOMEcần phải được trích dẫn hoặc chia + toàn cầu áp dụng trong shell khác zsh.
Stéphane Chazelas

@sch xin lỗi, nhưng liên kết bạn cung cấp trong bình luận dẫn đến một câu hỏi về chuột quang, không đề cập đến việc mở rộng dấu ngã. Bạn có thể vui lòng giải thích điều đó?
Sergiy Kolodyazhnyy

Câu trả lời tốt. Nó tóm tắt về cơ bản những gì bashcác trạng thái thủ công trong Tilde Expansionphần. +1
Sergiy Kolodyazhnyy

Xin lỗi, tôi đã quá quen với việc sử dụng các liên kết nội bộ trong unix.SE vì [link](/a/146697)tôi không nhận ra chúng tôi đang ở một trang web khác ở đây. Liên kết nên ở đó
Stéphane Chazelas
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.