Perché non ho potuto usare '~' invece di '/ home / nomeutente /' quando ho dato il percorso del file


43

Posso usare ~invece di /home/username/indicare un percorso di file quando, ad esempio, decomprimere un .zipfile.

Tuttavia, oggi quando ho seguito lo stesso modo per eseguire un esempio RNN nel terminale, è tensorflow.python.framework.errors_impl.NotFoundErrorstato lanciato.

$ 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

Poi ho sostituito ~con /home/username/, e ha funzionato correttamente.

Perché non posso usare ~invece di /home/username/puntare al percorso del file quando eseguo un esempio RNN?

Potresti dirmelo in dettaglio?




@OskarSkog La shell non dovrebbe espandersi ~prima che l'argomento venga passato a Python? Proprio come la shell espande le barre rovesciate nel percorso o rimuove le virgolette se il percorso fosse citato.
Micheal Johnson,

1
Diversamente $VARIABLES, ~viene espanso solo all'inizio di una stringa.
alexis

@OskarSkog, "Python non sa cosa ~ significa" implica che un problema è specifico di Python manca un pezzo di funzionalità, la creazione di un'aspettativa irragionevole che tale funzionalità (di eseguire l'espansione dopo essere exec'd) dovrebbe essere ampiamente disponibile in strumenti UNIX .
Charles Duffy,

Risposte:


45

Devi capire che ~normalmente viene espanso dalla shell; i programmi che chiami non lo vedono mai, vedono il percorso completo come inserito da bash. Ma questo succede solo quando la tilde è all'inizio di una discussione (e non è citata).

Se il programma Python in esecuzione utilizza un modulo come getoptper analizzarne la riga di comando, è possibile fornire l'argomento --data-pathdell'opzione come "parola" separata per consentire l'espansione della tilde:

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

Nel tuo codice, puoi utilizzare getopto argparseper l'elaborazione degli argomenti e puoi anche espandere manualmente le tilde come suggerito dalla risposta di @ JacobVlijm.

PS. La tilde viene inoltre espansa all'inizio di un'espressione di assegnazione di variabili shell come DIRNAME=~/anaconda2; sebbene la tilde nella tua domanda segua anche un segno di uguale, questo uso non ha un significato speciale per la shell (è solo qualcosa passato a un programma) e non attiva l'espansione.


6
A meno che tu non lo sappia getopt già, usa argparsese stai scrivendo Python.
Nick T

Ho aggiunto argparsealla risposta poiché è l'alternativa principale, ma personalmente trovo molto più difficile da usare rispetto a getopt, non più facile. YMMV.
alexis

33

Espansione tilde in pitone

La risposta è breve e semplice:

python non si espande ~se non si utilizza:

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

Vedi anche qui :

os.path.expanduser (percorso)
Su Unix e Windows, restituisce l'argomento con un componente iniziale di ~ o ~ utente sostituito dalla home directory dell'utente.

Su Unix, un ~ iniziale viene sostituito dalla variabile d'ambiente HOME se è impostata; in caso contrario la home directory dell'utente corrente viene cercata nella directory della password tramite il modulo incorporato pwd. Un utente ~ iniziale viene cercato direttamente nella directory delle password.


11
In generale, non dovresti mai supporre che l'espansione della tilde avvenga a livello di sistema operativo, è qualcosa che unix shell (e non tutte!) Fa per te.
farsil

1
Penso che il problema più rilevante sia delineato nella risposta di alexis: la posizione ~nella lista degli argomenti della shell.
David Foerster,

@farsil, non sono d'accordo. I programmi possono essere resi portatili, ma quando li esegui dalla riga di comando, lo fai su un sistema specifico. E non dimentichiamoci che questo è askubuntu.com e Ubuntu è sempre Unix ( per quanto ne sappiamo :-)
alexis

1
@alexis: Ubuntu non esegue nemmeno l'espansione tilde a livello di sistema operativo. È ancora funzionalità shell.
user2357112 supporta Monica

1
Pensa che stai dividendo i peli. Nessuno ha detto che il kernel lo stia facendo. Il punto è che non viene eseguito dal programma che accetta gli argomenti.
alexis

12

L'espansione di Tilde viene eseguita solo in alcuni contesti che variano leggermente tra le shell .

Mentre viene eseguito in:

var=~

O

export var=~

in alcune conchiglie. Non è dentro

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

nelle shell POSIX.

È presente bashquando non in modalità di conformità POSIX (come quando chiamato come sh, o quando si POSIXLY_CORRECTtrova nell'ambiente):

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

Tuttavia è solo quando ciò che è a sinistra di ha la =forma di un nome di variabile valido non quotato, quindi mentre sarebbe espanso in cmd prefix=~, non sarebbe in cmd --prefix=~(come --prefixnon è un nome di variabile valido) né in cmd "p"refix=~(a causa di quello citato p) né in var=prefix; cmd $var=~.

In zsh, è possibile impostare l' magic_equal_substopzione per ~l'espansione dopo qualsiasi non quotato =.

$ 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

Nel caso di ~(al contrario di ~user), puoi semplicemente usare $HOMEinvece:

cmd --whatever="$HOME/whatever"

~si espande al valore di $HOME. Se $HOMEnon impostato, il comportamento varia tra le shell. Alcune shell interrogano il database utente. Se vuoi tenerne conto, potresti fare (ed è anche quello per cui dovresti fare ~user):

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

In ogni caso, nelle shell diverse da quelle da zshricordare è necessario citare espansioni variabili!


1
Il manuale di riferimento di Bash sembra dire che le tilde si espandono solo su assegnazioni variabili e all'inizio di una parola, quindi l'espansione su di essa echo a=~sembra contraddire il manuale.
ilkkachu

@ilkkachu, sì, il manuale è incompleto. Inoltre non specifica chiaramente in quale contesto ~verrà espanso (cosa si intende per "parola"). Vedi il link nella parte superiore della risposta per maggiori dettagli.
Stéphane Chazelas,

6

~ha regole di espansione particolari, che il tuo comando non soddisfa. In particolare, viene espanso solo quando non quotato, all'inizio di una parola (ad es. python ~/script.py) O all'inizio di un'assegnazione variabile (ad es PYTHONPATH=~/scripts python script.py.). Quello che hai è --data_path=~/blablaquale è una singola parola in termini di shell, quindi l'espansione non viene eseguita.

Una soluzione immediata è usare la $HOMEvariabile shell, che segue le normali regole di espansione delle variabili:

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

È un po 'troppo semplificato, ci sono altri contesti in cui l'espansione della tilde viene eseguita come in PATH=$PATH:~/bin. Anche questo $HOMEdeve essere quotato o diviso + glob si applica in shell diverse da zsh.
Stéphane Chazelas,

@sch mi dispiace, ma il link che hai fornito nel commento lì porta a una domanda sul mouse ottico, senza menzione dell'espansione tilde. Puoi spiegarlo per favore?
Sergiy Kolodyazhnyy

Buona risposta. Riassume sostanzialmente ciò che il bashmanuale afferma nella Tilde Expansionsezione. +1
Sergiy Kolodyazhnyy

Siamo spiacenti, sono così abituato a utilizzare i collegamenti all'interno del sito in unix.SE come nel fatto [link](/a/146697)che non mi rendevo conto che eravamo su un sito diverso qui. Il collegamento dovrebbe essere
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.