Por que não posso usar '~' em vez de '/ home / username /' ao fornecer o caminho do arquivo

42

Eu posso usar ~ em vez de /home/username/ para apontar para um caminho de arquivo quando, por exemplo, descompactar um arquivo .zip .

No entanto, hoje, quando eu segui o mesmo caminho para executar um exemplo de RNN no terminal, tensorflow.python.framework.errors_impl.NotFoundError foi lançado.

$ 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

Então substituí ~ por /home/username/ e funcionou corretamente.

Por que não posso usar ~ em vez de /home/username/ para apontar para o caminho do arquivo ao executar um exemplo de RNN?

Você poderia me dizer em detalhes?

    
por JNing 07.03.2017 / 09:05

4 respostas

45

Você precisa entender que ~ é normalmente expandido pelo shell; os programas que você chama nunca o veem, eles vêem o caminho completo como inserido pelo bash. Mas isso só acontece quando o til está no início de um argumento (e não é citado).

Se o programa em Python que você está executando usa um módulo como getopt para analisar sua linha de comando, você pode dar o argumento da opção --data-path como uma "palavra" separada para permitir a expansão do til:

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

Em seu próprio código, você pode usar getopt ou argparse para o processamento de argumentos, e também pode expandir manualmente os tiles conforme a resposta de @ JacobVlijm sugerida.

PS. O til também é expandido no início de uma expressão de atribuição de variável shell como DIRNAME=~/anaconda2 ; embora o til na sua pergunta também siga um sinal de igual, esse uso não tem um significado especial para o shell (é apenas algo passado para um programa) e não ativa a expansão.

    
por alexis 07.03.2017 / 11:12
32

Expansão de til em python

A resposta é curta & simples:

python não expande ~ , a menos que você use:

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

Veja também aqui :

os.path.expanduser(path)
On Unix and Windows, return the argument with an initial component of ~ or ~user replaced by that user‘s home directory.

On Unix, an initial ~ is replaced by the environment variable HOME if it is set; otherwise the current user’s home directory is looked up in the password directory through the built-in module pwd. An initial ~user is looked up directly in the password directory.

    
por Jacob Vlijm 07.03.2017 / 09:19
12

Expansão de til é feita apenas em alguns contextos que variam ligeiramente entre os shells .

Enquanto é realizado em:

var=~

Ou

export var=~

em algumas conchas. Não está em

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

em shells POSIX.

Ele está em bash quando não está no modo de conformidade POSIX (como quando chamado como sh ou quando POSIXLY_CORRECT está no 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=~

No entanto, somente quando o lado esquerdo do = tiver o formato de um nome de variável válido sem aspas, ele será expandido em cmd prefix=~ e não será em cmd --prefix=~ (como --prefix is não é um nome de variável válido) nem em cmd "p"refix=~ (por causa disso, citada p ) nem em var=prefix; cmd $var=~ .

Em zsh , você pode definir a opção magic_equal_subst para ~ a ser expandida após qualquer = sem aspas.

$ 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

No caso de ~ (em oposição a ~user ), você pode usar apenas $HOME :

cmd --whatever="$HOME/whatever"

~ expande para o valor de $HOME . Se $HOME não estiver definido, o comportamento varia entre os shells. Alguns shells consultam o banco de dados do usuário. Se você quiser levar isso em conta, você pode fazer (e isso também é o que você teria que fazer para ~user ):

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

Em qualquer caso, em shells que não sejam zsh , lembre-se de citar expansões variáveis!

    
por Stéphane Chazelas 07.03.2017 / 12:03
6

~ tem regras de expansão específicas, que seu comando não satisfaz. Especificamente, ele é expandido apenas quando não estiver em destaque, seja no início de uma palavra (por exemplo, python ~/script.py ) ou no início de uma atribuição de variável (por exemplo, PYTHONPATH=~/scripts python script.py ). O que você tem é --data_path=~/blabla , que é uma única palavra em termos de shell, portanto, a expansão não é executada.

Uma correção imediata é usar a variável $HOME shell, que segue regras de expansão de variáveis regulares:

python ptb_word_lm.py --data_path=$HOME/blabla
    
por Dmitry Grigoryev 07.03.2017 / 11:28