Страницы

Поиск по вопросам

вторник, 25 февраля 2020 г.

./filename.py : No such file or directory

#python #bash


Питоновский скрипт находится в некой папке.
В начале файла прописано 

#!/usr/bin/env python


Так же была выполнена команда chmod u+x ./filename.py 
при попытке запустить из терминала ./filename.py отвечает :


  No such file or directory


Вывод ls -lh:

-rwx--x--x 1 User User 9.8K Sep 27 16:01 filename.py


Вывод which python:

/usr/bin/python


Были испробованы от безысходности так же

#!/usr/bin/python python
#!/usr/bin/python

    


Ответы

Ответ 1



tl;dr: см. Выводы внизу Чтобы понять откуда берётся пустое имя файла (слева от : в сообщении об ошибке): >>> import os >>> os.system('./hi.py') : No such file or directory 32512 можно вызвать команду напрямую без оболочки (такой как bash): >>> from subprocess import Popen, PIPE >>> Popen('./hi.py', stdout=PIPE, stderr=PIPE).communicate() (b'', b'/usr/bin/env: python\r: No such file or directory\n') результат говорит, что b'\r' распознаётся как часть имени команды. На POSIX системах имя файла может быть произвольной последовательностью байтов (кроме нуля b'\0' и слэша b'/'). Если создать исполняемый файл в PATH, который имеет имя b'python\r': >>> os.symlink('/usr/bin/python', os.path.expanduser('~/bin/python\r')) то ошибка исчезает: >>> os.system('./hi.py') hi! 0 где hi.py простой исполняемый скрипт Питона с Виндовыми окончаниями строк: >>> open('hi.py', 'wb').write(b'#!/usr/bin/env python\r\nprint("hi!")') >>> os.chmod('hi.py', 0b111101101) # rwxr-xr-x Имя команды не видно в первом примере, потому что b'\r' в терминале переводит курсор в начало строки: >>> print('abc\r12') 12c то есть буквы ab забиваются цифрами 12 в данном примере. Пример демонстрирует традиционное поведение для CR (carriage return). Сам python поддерживает универсальный режим новых строк и поэтому работает с '\r\n' и на Unix: >>> os.unlink(os.path.expanduser('~/bin/python\r')) >>> os.system('python ./hi.py') hi! 0 #!-строку (shebang) распознаёт не python, и даже не bash, а ядро операционной системы (Linux, к примеру). По умолчанию современные версии Unix игнорируют горизонтальный пробел (пробел b' ' и таб b'\t') в конце #!-строки: >>> import string >>> for ws in string.whitespace: ... with open('space[%X].py' % ord(ws), 'w') as f: ... f.write('#!/usr/bin/env python%s\nprint("%X")' % (ws, ord(ws))) >>> from glob import glob >>> for cmd in glob('./spac*.py'): ... os.chmod(cmd, 0b111101101) ... Popen(cmd, stdout=PIPE, stderr=PIPE).communicate() ... (b'', b'/usr/bin/env: python\r: No such file or directory\n') (b'20\n', b'') (b'A\n', b'') (b'', b'/usr/bin/env: python\x0b: No such file or directory\n') (b'9\n', b'') (b'', b'/usr/bin/env: python\x0c: No such file or directory\n') То есть команда работает для ' \n\t' и не работает для '\r\v\f'. Если хочется запускать скрипт напрямую (не указывая интерпретёр явно), то следует использовать Юниксовые окончания строк, как предложил @alexander barakin: >>> data = open('./hi.py', 'rb').read() >>> open('./hi.py', 'wb').write(data.replace(b'\r\n', b'\n')) 34 >>> os.system('./hi.py') hi! 0 Системы контроля версий такие как Mercurial (hg), git наверняка имеют опции, которые помогут заменить новые строки текущей операционной системы на \n для .py файлов автоматически, если нет возможности использовать редактор, который подерживает \n напрямую. Если автор команды, реализованной на Питоне, сам работает только на Винде и не хочет усложнять процесс, то создав setup.py, который определяет setuptools' entry_points, можно автоматически поддерживать разные системы (если других несовместимостей нет): from setuptools import setup setup(name='program', version='1.2.5', description='', long_description='', author='', author_email='', url='', license='', py_modules=['program'], entry_points={ 'console_scripts': ['program=program:main'] } ) где program.py файл, для примера, мог быть создан на Винде: >>> open('program.py', 'wb').write(b'#!/usr/bin/env python\r\ndef main():\r\n print("hi!")\r\n') 52 При инсталляции создаются скрипты с правильной #!-строкой на Unix системах и соответствующие .exe файлы на Windows: >>> import subprocess >>> import sys >>> subprocess.call([sys.executable] + '-m pip install -e .'.split()) Obtaining file:///tmp/prj Installing collected packages: program Running setup.py develop for program Successfully installed program-1.2.5 0 >>> subprocess.call('program') hi! 0 Прямое чтение машинно-сгенерированного файла подтверждает, что '\n' используется на Unix (docker run -v $PWD:/tmp/prj -it --rm python) системе: >>> import shutil >>> open(shutil.which('program'), 'rb').readline() b'#!/usr/local/bin/python3\n' Выводы '\r' в #!-строке рассматривается как часть имени команды (b'python\r') на некоторых системах, что вызывает ошибку: "No such file or directory" при попытке запуска скрипта некоторые терминалы, встречая '\r' в выводе программы, переводят курсор в начало строки, поэтому имя файла в сообщении об ошибке (часть слева от двоеточия) кажется пустым (текст сообщения напечатан поверх него) не ясно почему Linux ядро не игнорирует '\r' в конце #!-строки, как оно это делает для пробелов и табов. Возможно такой выбор сделан, чтобы как раз помочь заметить, что скрипт имеет несовместимые окончания строк (что может указывать на другие проблемы с переносимостью в программе) предпочтительный способ обхода этой проблемы—использование редактора, который поддерживает '\n' на Windows. Или же, если разработка ведётся исключительно на Винде, то создание setup.py с setuptools' entry_points как показано выше, чтобы при инсталляции правильные для платформы скрипты-обёртки генерировались бы автоматически.

Ответ 2



алгоритм поиска возможных причин подобной ошибки: возможно, в начале файла есть bom-ы или в первые строки «затесались» другие нечитабельные символы, что можно обнаружить, просматривая файл побайтово, например, так: $ hexdump -C файл | less про удаление bom-ов: Как убрать BOM из файла? возможно, в начале файла присутствуют переводы строк «не той системы» (для unix-like должны быть \n, оно же lf, т.е. linefeed, шестнадцатиричный код 0x0a), либо их смесь. как проверить — см. предыдущий пункт. исправить «досовские» cr+lf (\r\n, шестнадцатиричной код 0x0d 0x0a) можно, например, с помощью прогарммы dos2unix (из одноимённого пакета): $ dos2unix файл исправить «маковский» cr (\r, шестнадцатиричной код 0x0d) можно, например, с помощью прогарммы mac2unix (из того же пакета, что и выше): $ mac2unix файл

Комментариев нет:

Отправить комментарий