ทำไมฉันไม่สามารถใช้ '~' แทน '/ home / ชื่อผู้ใช้ /' เมื่อให้เส้นทางของไฟล์


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/และมันทำงานได้อย่างถูกต้อง

ทำไมฉันไม่สามารถใช้~แทน/home/username/การชี้ไปที่เส้นทางของไฟล์เมื่อเรียกใช้ตัวอย่าง RNN ได้

คุณสามารถบอกรายละเอียดฉันได้ไหม




@OskarSkog ไม่ควรขยายเชลล์~ก่อนที่อาร์กิวเมนต์จะถูกส่งไปยัง python หรือไม่ เช่นเดียวกับที่เชลล์จะขยายเครื่องหมายแบ็กสแลชในพา ธ หรือลบเครื่องหมายคำพูดหากอ้างถึงเส้นทาง
Micheal Johnson

1
ซึ่งแตกต่างจาก$VARIABLESการ~ขยายเท่านั้นที่จุดเริ่มต้นของสตริง
alexis

@OskarSkog, "งูใหญ่ไม่ทราบว่า ~ หมายถึง" หมายความว่าปัญหาเป็นเฉพาะกับงูหลามขาดชิ้นส่วนของการทำงาน, การตั้งค่าความคาดหวังที่ไม่สมควรว่าการทำงานดังกล่าว (ในการดำเนินการขยายตัวหลังจากถูกexec'd) ควรจะพร้อมใช้งานกันอย่างแพร่หลายในเครื่องมือยูนิกซ์ .
Charles Duffy

คำตอบ:


45

คุณต้องเข้าใจว่า~โดยปกติแล้วเชลล์จะขยายออก โปรแกรมที่คุณโทรหาจะไม่เห็นมันพวกเขาเห็นชื่อพา ธ เต็มว่าถูกแทรกโดยทุบตี แต่สิ่งนี้จะเกิดขึ้นก็ต่อเมื่อตัวหนอนเป็นจุดเริ่มต้นของการโต้แย้ง (และไม่มีการอ้างถึง)

หากโปรแกรม Python ที่คุณใช้งานอยู่นั้นใช้โมดูลที่ต้องการgetoptแจงบรรทัดคำสั่งคุณสามารถให้อาร์กิวเมนต์ของ--data-pathตัวเลือกเป็น "word" แยกต่างหากเพื่ออนุญาตการขยายตัวของ tilde:

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

ในรหัสของคุณเองคุณสามารถใช้getoptหรือargparseสำหรับการประมวลผลการโต้แย้งและยังสามารถขยายตัวหนอนด้วยตนเองตามคำแนะนำของ @ JacobVlijm

PS เครื่องหมายตัวหนอนจะถูกขยายเมื่อเริ่มต้นของนิพจน์การกำหนดตัวแปรเชลล์เช่นDIRNAME=~/anaconda2; แม้ว่าเครื่องหมายตัวหนอนในคำถามของคุณจะเป็นไปตามเครื่องหมายเท่ากับการใช้งานนี้ไม่มีความหมายพิเศษสำหรับเชลล์ (เป็นเพียงบางสิ่งที่ส่งผ่านไปยังโปรแกรม) และไม่กระตุ้นการขยายตัว


6
นอกจากว่า คุณรู้getoptแล้วให้ใช้argparseถ้าคุณกำลังเขียน Python
Nick T

ฉันได้เพิ่มargparseคำตอบเนื่องจากเป็นตัวเลือกหลัก แต่โดยส่วนตัวแล้วฉันพบว่ามันใช้งานได้ยากกว่าgetoptไม่ใช่ง่ายกว่า YMMV
alexis

33

ขยายตัวหนอนในงูหลาม

คำตอบสั้น & ง่าย:

หลามไม่ได้ขยาย~จนกว่าคุณจะใช้:

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

ดูที่นี่ :

os.path.expanduser (เส้นทาง)
บน Unix และ Windows ให้ส่งคืนอาร์กิวเมนต์ด้วยองค์ประกอบเริ่มต้นของผู้ใช้ ~ หรือ ~ ที่ถูกแทนที่ด้วยโฮมไดเรกทอรีของผู้ใช้นั้น

บน Unix ค่าเริ่มต้น ~ จะถูกแทนที่ด้วยตัวแปรสภาพแวดล้อม HOME หากตั้งค่าไว้ มิฉะนั้นโฮมไดเร็กทอรีของผู้ใช้ปัจจุบันจะถูกค้นหาในไดเร็กทอรีรหัสผ่านผ่านโมดูลในตัว pwd ผู้ใช้เริ่มต้น ~ ถูกค้นหาโดยตรงในไดเรกทอรีรหัสผ่าน


11
โดยทั่วไปคุณไม่ควรสรุปว่าการขยายตัวหนอนจะทำในระดับ OS มันเป็นสิ่งที่ยูนิกซ์เชลล์ (และไม่ใช่ทั้งหมด!) ทำเพื่อคุณ
ฟา

1
ฉันคิดว่าปัญหาที่เกี่ยวข้องมากขึ้นอยู่ในคำตอบของ alexis: ตำแหน่งของ~รายการอาร์กิวเมนต์ shell
David Foerster

@farsil ฉันไม่เห็นด้วย โปรแกรมสามารถทำแบบพกพาได้ แต่เมื่อคุณเรียกใช้จากบรรทัดคำสั่งคุณจะทำในระบบที่ระบุ และอย่าลืมว่านี่คือ askubuntu.com และ Ubuntu มักจะเป็น Unix ( เท่าที่เรารู้ :-)
alexis

1
@alexis: Ubuntu ไม่ได้ทำการขยายตัวหนอนที่ระดับ OS เช่นกัน มันเป็นฟังก์ชั่นของเชลล์
user2357112

1
คิดว่าคุณแยกขน ไม่มีใครบอกว่าเคอร์เนลกำลังทำอะไรอยู่ ประเด็นก็คือมันไม่ได้ทำโดยโปรแกรมที่ใช้อาร์กิวเมนต์
alexis

12

การขยายตัวหนอนจะทำเฉพาะในไม่กี่บริบทที่แตกต่างกันเล็กน้อยระหว่างเปลือกหอย

ในขณะที่มันจะดำเนินการใน:

var=~

หรือ

export var=~

ในหอยบางตัว มันไม่ได้อยู่ใน

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

ใน POSIX เชลล์

มันอยู่ใน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ตัวเลือกสำหรับการ~ที่จะขยายตัวหลังจาก =unquoted

$ 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 ดูเหมือนจะบอกว่า tildes นั้นจะขยายเฉพาะในการกำหนดตัวแปรและเมื่อเริ่มต้นของคำดังนั้นการขยายecho a=~ไปยังที่ดูเหมือนจะขัดแย้งกับคู่มือ
ilkkachu

@ilkkachu ใช่คู่มือไม่สมบูรณ์ นอกจากนี้ยังไม่ได้ระบุอย่างชัดเจนในบริบทที่~จะขยาย (ความหมายโดย "คำว่า") ดูลิงค์ที่ด้านบนของคำตอบสำหรับรายละเอียดเพิ่มเติม
Stéphane Chazelas

6

~มีกฎการขยายโดยเฉพาะซึ่งคำสั่งของคุณไม่เป็นไปตาม โดยเฉพาะมันจะขยายเฉพาะเมื่อไม่ได้ยกมาทั้งที่จุดเริ่มต้นของคำ (เช่นpython ~/script.py) หรือที่จุดเริ่มต้นของการกำหนดตัวแปร (เช่นPYTHONPATH=~/scripts python script.py) สิ่งที่คุณมีคือ --data_path=~/blablaคำใดคำหนึ่งในเงื่อนไขเชลล์ดังนั้นการขยายจะไม่ดำเนินการ

การแก้ไขทันทีคือการใช้$HOMEตัวแปรเชลล์ซึ่งเป็นไปตามกฎการขยายตัวของตัวแปรปกติ:

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

นั่นเป็นเรื่องเล็กน้อยเกินจริงมีบริบทอื่น ๆ ที่มีการขยายตัวของตัวหนอนจะดำเนินการเหมือนPATH=$PATH:~/binมา นอกจากนี้ที่$HOMEความต้องการที่จะยกมาหรือแยก + glob ใช้ในเปลือกหอยอื่น ๆ zshกว่า
Stéphane Chazelas

@sch ขออภัย แต่ลิงค์ที่คุณให้ไว้ในความคิดเห็นนั้นนำไปสู่คำถามเกี่ยวกับออปติคัลเมาส์โดยไม่มีการกล่าวถึงส่วนขยายตัวหนอน คุณช่วยอธิบายได้มั้ย
Sergiy Kolodyazhnyy

คำตอบที่ดี. มันสรุปโดยทั่วไปสิ่งที่bashรัฐคู่มือในTilde Expansionส่วน +1
Sergiy Kolodyazhnyy

ขออภัยฉันคุ้นเคยกับการใช้ลิงก์ภายในไซต์ในยูนิกซ์เช่นเดียวกับ[link](/a/146697)ที่ฉันไม่รู้ว่าเราอยู่ในไซต์อื่นที่นี่ ลิงก์ควรไปที่นั่น
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.