Dlaczego nie mogłem użyć „~” zamiast „/ home / username /” podczas podawania ścieżki do pliku

43

Mogę użyć ~zamiast /home/username/wskazywać ścieżkę do pliku, na przykład podczas rozpakowywania .zippliku.

Jednak dzisiaj, gdy poszedłem w ten sam sposób, aby uruchomić przykład RNN w terminalu, tensorflow.python.framework.errors_impl.NotFoundErrorzostał rzucony.

$ 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

Wtedy otrzymuje ~się /home/username/, i to działało poprawnie.

Dlaczego nie mogę użyć ~zamiast /home/username/wskazywać ścieżki pliku podczas uruchamiania przykładu RNN?

Czy mógłbyś mi szczegółowo powiedzieć?

JNing
źródło
Czy ~ zawsze równa się $ HOME
Stéphane Chazelas
@OskarSkog Czy powłoka nie powinna rozwinąć ~przed przekazaniem argumentu do Pythona? Podobnie jak powłoka rozwijałaby ucieczki ukośnika odwrotnego na ścieżce lub usuwała cudzysłowy, jeśli ścieżka była cytowana.
Micheal Johnson
1
W przeciwieństwie do $VARIABLEStego ~jest rozwinięty tylko na początku łańcucha.
Alexis
@OskarSkog, „Python nie wie, co oznacza ~” oznacza, że ​​problem jest specyficzny dla Pythona pozbawionego jakiejś funkcjonalności, co powoduje nieuzasadnione oczekiwanie, że taka funkcjonalność (wykonywanie rozszerzenia po byciu execd) powinna być szeroko dostępna w narzędziach UNIX .
Charles Duffy

Odpowiedzi:

45

Musisz zrozumieć, że ~zwykle jest rozszerzany przez powłokę; programy, które wywołujesz, nigdy tego nie widzą, widzą pełną nazwę ścieżki wstawioną przez bash. Ale dzieje się tak tylko wtedy, gdy tylda jest na początku argumentu (i nie jest cytowana).

Jeśli uruchomiony program Python używa modułu takiego jak getoptparsowanie wiersza poleceń, możesz podać argument --data-pathopcji jako osobne „słowo”, aby umożliwić rozwinięcie tyldy:

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

W swoim własnym kodzie możesz używać getoptlub argparsedo przetwarzania argumentów, a także możesz ręcznie rozwijać tyldy, jak sugeruje odpowiedź @ JacobVlijm.

PS. Tylda jest także rozszerzona na początku powłoki przypisania ekspresji zmiennej jak DIRNAME=~/anaconda2; chociaż tylda w twoim pytaniu również występuje po znaku równości, to użycie nie ma specjalnego znaczenia dla powłoki (jest to po prostu coś przekazywanego do programu) i nie powoduje rozszerzenia.

Alexis
źródło
6
Jeśli nie wiesz getopt , użyj, argparsejeśli piszesz w języku Python.
Nick T
Dodałem argparsedo odpowiedzi, ponieważ jest to główna alternatywa, ale osobiście uważam, że jest znacznie trudniejsza w użyciu niż getoptwcale nie jest łatwiejsza. YMMV.
Alexis
33

Rozszerzenie tyldy w pythonie

Odpowiedź jest krótka i prosta:

Python nie rozwija się, ~chyba że użyjesz:

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

Zobacz także tutaj :

os.path.expanduser (ścieżka)
W systemach Unix i Windows zwróć argument z początkowym składnikiem ~ lub ~ użytkownika zastąpionym katalogiem osobistym tego użytkownika.

W systemie Unix wartość początkowa ~ jest zastępowana zmienną środowiskową HOME, jeśli jest ustawiona; w przeciwnym razie katalog domowy bieżącego użytkownika zostanie wyszukany w katalogu haseł przez wbudowany moduł pwd. Początkowy ~ użytkownik jest wyszukiwany bezpośrednio w katalogu haseł.

Jacob Vlijm
źródło
11
Ogólnie rzecz biorąc, nigdy nie należy zakładać, że rozszerzanie tyldy odbywa się na poziomie systemu operacyjnego, jest to coś, co robią dla ciebie powłoki unixowe (i nie wszystkie!).
farsil
1
Wydaje mi się, że bardziej trafny problem jest ujęty w odpowiedzi Alexis: pozycja ~na liście argumentów powłoki.
David Foerster,
@farsil, nie zgadzam się. Programy można uczynić przenośnymi, ale uruchamiając je z wiersza poleceń, robisz to w określonym systemie. I nie zapominajmy, że jest to askubuntu.com, a Ubuntu jest zawsze uniksowy ( o ile wiemy :-)
Alexis
1
@alexis: Ubuntu nie rozszerza tyldy na poziomie systemu operacyjnego. To wciąż funkcjonalność powłoki.
user2357112,
1
Myślisz, że dzielisz włosy. Nikt nie powiedział, że jądro to robi. Chodzi o to, że program nie pobiera argumentów.
Alexis
12

Rozbudowa tyldy odbywa się tylko w kilku kontekstach, które różnią się nieznacznie między powłokami .

Podczas gdy jest wykonywany w:

var=~

Lub

export var=~

w niektórych muszlach. Nie ma go

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

w powłokach POSIX.

Dzieje się tak, bashgdy nie jest w trybie zgodności z POSIX (np. Gdy jest wywoływany jako shlub gdy POSIXLY_CORRECTznajduje się w środowisku):

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

Jednak tylko wtedy, gdy to, co znajduje się po lewej stronie =jest ukształtowane jak niecytowana poprawna nazwa zmiennej, więc chociaż będzie ona rozwinięta cmd prefix=~, nie będzie w cmd --prefix=~(ponieważ --prefixnie jest prawidłową nazwą zmiennej) ani w cmd "p"refix=~(z powodu tego cytowanego p) ani w var=prefix; cmd $var=~.

W zshpolu możesz ustawić magic_equal_substopcję ~rozwijania po każdym nie cytowanym =.

$ 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

W przypadku ~(w przeciwieństwie do ~user) możesz po prostu użyć $HOMEzamiast tego:

cmd --whatever="$HOME/whatever"

~rozwija się do wartości $HOME. Jeśli $HOMEnie jest ustawiony, zachowanie różni się między powłokami. Niektóre powłoki wykonują zapytania do bazy danych użytkowników. Jeśli chcesz to wziąć pod uwagę, możesz zrobić (i to też musisz zrobić ~user):

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

W każdym razie, w powłokach innych niż zshpamiętaj, musisz cytować zmienne rozszerzenia!

Stéphane Chazelas
źródło
1
Wydaje się, że podręcznik referencyjny Bash mówi, że tyldy są rozwijane tylko przy przypisywaniu zmiennych i na początku słowa, więc rozwijanie go echo a=~wydaje się być sprzeczne z instrukcją.
ilkkachu
@ilkkachu, tak instrukcja jest niekompletna. Nie określa też jasno, w jakim kontekście ~zostanie rozwinięty (co oznacza „słowo”). Zobacz link u góry odpowiedzi, aby uzyskać więcej informacji.
Stéphane Chazelas
6

~ma określone reguły rozszerzania, których twoje polecenie nie spełnia. W szczególności jest rozszerzany tylko wtedy, gdy nie jest cytowany, ani na początku słowa (np. python ~/script.py) , Ani na początku przypisania zmiennej (np PYTHONPATH=~/scripts python script.py.). To, co masz, jest --data_path=~/blablapojedynczym słowem w terminologii powłoki, więc ekspansja nie jest wykonywana.

Natychmiastową poprawką jest użycie $HOMEzmiennej powłoki, która jest zgodna ze zwykłymi regułami rozszerzania zmiennych:

python ptb_word_lm.py --data_path=$HOME/blabla
Dmitrij Grigoriew
źródło
To trochę uproszczone, istnieją inne konteksty, w których rozszerzanie tyldy odbywa się jak w PATH=$PATH:~/bin. Również to $HOMEmusi być cytowane lub podzielone + glob ma zastosowanie w powłokach innych niż zsh.
Stéphane Chazelas,
@sch przepraszam, ale link podany w komentarzu prowadzi do pytania o mysz optyczną, bez wzmianki o rozszerzeniu tyldy. Czy możesz to wyjaśnić?
Sergiy Kolodyazhnyy
Dobra odpowiedź. Podsumowuje w zasadzie, co bashstanowi instrukcja w tej Tilde Expansionsekcji. +1
Sergiy Kolodyazhnyy
Przepraszam, jestem tak przyzwyczajony do używania linków wewnątrz witryny w unix.SE [link](/a/146697), że nie zdawałem sobie sprawy, że jesteśmy tutaj na innej stronie. Link powinien być tam
Stéphane Chazelas