提供文件路径时,为什么不能使用'〜'而不是'/ home / username /'


43

例如,在解压缩文件时,我可以使用~而不是/home/username/指向文件路径.zip

但是,今天,当我按照同样的方式在终端中运行RNN示例时,tensorflow.python.framework.errors_impl.NotFoundError就被抛出了。

$ 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

然后,我将其替换~/home/username/,并且它可以正常工作。

为什么在运行RNN示例时不能使用~而不是/home/username/指向文件路径?

您能详细告诉我吗?




@OskarSkog ~在将参数传递给python之前,外壳程序是否应该展开?就像shell会在路径中扩展反斜杠转义符一样,或者在路径被引用的情况下删除引号。
米歇尔·约翰逊

1
与不同$VARIABLES~只能在字符串的开头扩展。
Alexis

@OskarSkog,“Python不知道是什么〜手段”意味着一个问题是针对Python缺少一块的功能,设置不合理的预期(的执行扩张这样的功能之后exec“d)应该是在UNIX工具广泛使用。
Charles Duffy

Answers:


45

您需要了解~通常是由Shell扩展的。您调用的程序永远不会看到它,它们会看到bash插入的完整路径名。但这仅在波浪号位于参数的开头(并且不加引号)时发生。

如果您正在运行的Python程序使用一个模块getopt来解析其命令行,则可以将--data-path选项的参数作为单独的“单词”提供以允许波浪号扩展:

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

在您自己的代码中,您可以使用getoptargparse进行参数处理,也可以按照@JacobVlijm的答案建议手动扩展波浪号。

PS。代字号还在shell变量赋值表达式(如DIRNAME=~/anaconda2;)的开头扩展。尽管问题中的波浪号也跟随等号,但是这种用法对shell没有特殊意义(只是传递给程序的东西),并且不会触发扩展。


6
除非已经知道 getoptargparse否则在编写Python时使用。
尼克T

我已经添加argparse了答案,因为它是主要的选择,但就我个人而言,它的使用难度要大得多getopt,而不是要容易得多。YMMV。
亚历克西斯

33

python中的Tilde扩展

答案很简单:

~除非您使用以下命令,否则python不会扩展:

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

也可以在这里查看

os.path.expanduser(path)
在Unix和Windows上,返回带有〜或〜user初始组成部分的参数,并替换为该用户的主目录。

在Unix上,如果设置了首字母〜,则由环境变量HOME代替;否则,将通过内置模块pwd在密码目录中查找当前用户的主目录。最初的〜user直接在password目录中查找。


11
通常,您永远不应该假设波浪号扩展是在操作系统级别完成的,这是unix shell(并非全部都是shell)为您完成的事情。
farsil

1
我认为alexis的答案列出了更相关的问题:~shell参数列表中的位置。
David Foerster'3

@farsil,我不同意。可以使程序具有可移植性,但是从命令行运行它们时,是在特定系统上执行的。而且请不要忘记这是askubuntu.com,而Ubuntu始终是Unix(据我们所知 :-)
Alexis

1
@alexis:Ubuntu也不在操作系统级别进行波浪线扩展。它仍然是外壳程序功能。
user2357112

1
我认为你在分裂头发。没有人说内核正在这样做。关键是,接受参数的程序并没有做到这一点。
Alexis

12

仅在少数情况下才能完成Tilde扩展,并且在各个shell之间会有一些细微的差异

在以下情况下执行:

var=~

要么

export var=~

在一些贝壳中。不在

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

在POSIX shell中。

它是bash虽然当不符合POSIX模式(比如当称为sh,或者POSIXLY_CORRECT在环境中):

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

但是,只有当其左侧的=形状像未加引号的有效变量名一样时,因此,尽管将其扩展为cmd prefix=~,但它不会位于cmd --prefix=~(因为--prefix不是有效的变量名),也不会位于cmd "p"refix=~(因为该引号p)或在var=prefix; cmd $var=~

在中zsh,您可以将magic_equal_subst选项设置为~在任何未引用的位置后展开=

$ 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

对于~(与相对~user),您可以使用$HOME代替:

cmd --whatever="$HOME/whatever"

~扩展为的值$HOME。如果$HOME未设置,则外壳之间的行为会有所不同。一些外壳程序查询用户数据库。如果您要考虑到这一点,可以这样做(这也是您必须要做的~user):

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

无论如何,在其他外壳程序中,zsh请记住要引用变量扩展!


1
Bash的参考手册似乎说波浪号仅在变量赋值和单词开头处扩展,因此将其扩展echo a=~似乎与该手册矛盾。
ilkkachu

@ilkkachu,是的,手册不完整。它也没有明确指出~将在什么上下文中扩展(“单词”的含义)。有关更多详细信息,请参见答案顶部的链接。
斯特凡Chazelas

6

~具有特定的扩展规则,您的命令无法满足这些规则。具体来说,仅当未加引号时,才在单词的开头(例如python ~/script.py)或变量赋值的开头(例如)将其扩展PYTHONPATH=~/scripts python script.py。您拥有的是 --data_path=~/blabla用shell术语来讲的一个词,因此不执行扩展。

一个直接的解决方法是使用$HOME外壳变量,该变量遵循常规的变量扩展规则:

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

有点过分简化了,在其他情况下,如一样执行了波浪号扩展PATH=$PATH:~/bin。另外,$HOME需要将其引起引用,或者split + glob应用于除以外的其他shell zsh
斯特凡Chazelas

@sch很抱歉,但是您在注释中提供的链接导致了有关光电鼠标的问题,而没有提及波浪号扩展。你能解释一下吗?
Sergiy Kolodyazhnyy

好答案。它基本上总结bash了本Tilde Expansion节中手册的内容。+1
Sergiy Kolodyazhnyy

抱歉,我习惯在unix.SE中使用站点内链接,因为[link](/a/146697)我没有意识到我们在这里是另一个站点。链接应该是
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.