Неможливо передати аргумент python з “#! / Usr / bin / env python”


76

Мені потрібно було безпосередньо виконувати скрипт python, тому я запустив файл з #!/usr/bin/env python. Однак мені також потрібен негативний вихід, тому я спробував #!/usr/bin/env python -u, але це не вдається python -u: no such file or directory.

Я виявив, що це #/usr/bin/python -uпрацює, але мені це потрібно, щоб увійти pythonв систему PATHдля підтримки віртуальних envсередовищ.

Які у мене варіанти?


1
Ви можете поглянути на це запитання SO, щоб отримати трохи інформації про те, як робити негарний вихід.
Маттіас Нільссон,

Відповіді:



43

У деяких середовищах env не розділяє аргументи. Отже, ваша env шукаєpython -u вашому шляху. Ми можемо використовувати sh, щоб обійти. Замініть свій шебанг наступними рядками коду, і все буде добре.

#!/bin/sh
''''exec python -u -- "$0" ${1+"$@"} # '''
# vi: syntax=python

ps нам не потрібно турбуватися про шлях до sh, так?


2
Для тих, хто цікавиться, як це працює: Чому працює цей фрагмент?
Мартін Пітерс

14
${1+"$@"}хак , ймовірно , був непотрібним , принаймні , 20 років :)
user4815162342

2
Можливо, хакерство непотрібне, але це не шкодить, чи не так? Це цікаво знати про це :-) Я щойно про це дізнався сьогодні. У будь-якому випадку, я думаю, це "exec" "python" "-u" "--" "$0" "$@"може бути простіше зрозуміти - чи є в цьому якийсь недолік? (Я думаю, що це несумісно з 1+хакерством?)
Аарон Макдейд

1
У мого методу є недолік. Якщо ви хочете передати в bash щось складне, наприклад рядок із вкладеним 'або ", тоді ваш метод є більш надійним. Це цікаве питання! Моє легше зрозуміти, але ваше більш надійне. Можливо, ваша відповідь повинна пояснити, що вона повинна починатися з ''''exec, а рядок повинен закінчуватися # '''(пробілом перед знаком #). Поки ми дотримуємось цих правил і не маємо зайвих потрійних лапок ''', ваш метод ідеальний та гнучкий.
Аарон Макдейд

1
@ user4815162342 Ось докладніший контекст ${1+"$@"}. Тому "$@"в більшості випадків слід працювати нормально самостійно.
акхан

16

Це може бути трохи застарілим, але керівництво env (1) говорить, що для цього випадку можна використовувати '-S'

#!/usr/bin/env -S python -u

Здається, це досить добре працює на FreeBSD.


вау, було б добре, якби це працювало широко, але також не було доступним на cygwin :(
philwalk

6
Здається, -Sваріант є специфічним для варіанту BSD, env(1)але це добре знати
nodakai

3
Наразі Linux env -Sтеж є - станом на coreutils 8.30 1 (що може зайняти деякий час, щоб з’явитись у дистрибутиві поблизу вас). Та ж семантика, що і у FreeBSD env(1)- ура для перенесення хороших функцій.
Хуан

Не пощастило і на Solaris (11.3) ... :(
Тімма

16

Коли ви використовуєте shebang в Linux, весь інший рядок після імені інтерпретатора інтерпретується як єдиний аргумент. python -uПереходить в руки, envяк якщо б ви набрали: /usr/bin/env 'python -u'. У /usr/bin/envпошуках виконуваного файлу python -u, який є не один.


13

Передача аргументів у рядок shebang не є стандартною, і, як ви експериментували, не працює в поєднанні з env в Linux. Рішення з bash полягає у використанні вбудованої команди "set" для встановлення необхідних параметрів. Я думаю, ви можете зробити те саме, щоб встановити негарний вихід stdin за допомогою команди python.

my2c


9

Ось сценарій, альтернативний тому /usr/bin/env, що дозволяє передавати аргументи в рядок хеш-вибуху на основі /bin/bashта з обмеженням заборонених пробілів у виконуваному шляху. Я називаю це "envns" (env No Spaces):

#!/bin/bash

ARGS=( $1 )  # separate $1 into multiple space-delimited arguments.
shift # consume $1

PROG=`which ${ARGS[0]}`
unset ARGS[0] # discard executable name

ARGS+=( "$@" ) # remainder of arguments preserved "as-is".
exec $PROG "${ARGS[@]}"

Якщо припустити, що цей скрипт знаходиться за адресою / usr / local / bin / envns, ось ваш рядок shebang:

#!/usr/local/bin/envns python -u

Перевірено на Ubuntu 13.10 та cygwin x64.


2
Це слід
зв’язати

Примітка: Більшість Unix-іш #! реалізації не дозволяють використовувати сценарії з міркувань безпеки. Я здивований, що це спрацювало на Ubunut 13.10.
Хуан

також працює на ubuntu 16.04 станом на 20.01.2019, не впевнений в інших.
philwalk

5

Це клуб і вимагає bash, але він працює:

#!/bin/bash

python -u <(cat <<"EOF"
# Your script here
print "Hello world"
EOF
)

1
Дякую, це добре спрацювало для мене щодо іншої проблеми (використання оболонки mono csharp з аргументами)
IanNorton

4

Спираючись на відповідь Ларрі Кая, envви можете встановити змінну безпосередньо в командному рядку. Це означає, що -uможна замінити еквівалентним PYTHONUNBUFFEREDналаштуванням перед python:

#!/usr/bin/env PYTHONUNBUFFERED="YESSSSS" python

Працює над RHEL 6.5. Я майже впевнений, що ця особливість envмайже універсальна.


3
FYI, це НЕ працює в Debian. Я не впевнений, чому це не працює (якщо дивитись psвихідні дані, різниці не повинно бути), але це ніколи не повертається. Не зовсім зрозуміло, чи насправді сам python працює взагалі, коли ви робите це в Debian. Я спробував це в декількох місцях - точно не працює, як очікувалося, порівняно з еквівалентним командним рядком.
MartyMacGyver

@MartyMacGyver. Дуже ймовірно, це стосується версії envабо навіть pythonви використовуєте.
Божевільний фізик

Це може бути версія env, але поки що вона не працює з жодним сучасним варіантом Debian. Здається, що Python насправді не працює в цьому сценарії на Debian, що обмежує його використання за межами певних платформ та / або конфігурацій.
MartyMacGyver

-1

Нещодавно я написав патч для версії GNU Coreutils envдля вирішення цієї проблеми:

http://lists.gnu.org/archive/html/coreutils/2017-05/msg00018.html

Якщо у вас є це, ви можете зробити:

#!/usr/bin/env :lang:--foo:bar

envрозділиться :lang:foo:--barна поля lang, fooі --bar. Він буде шукати PATHперекладача lang, а потім викликати його з аргументами --foo,bar плюс шлях до сценарію і аргументи, скрипта.

Також є функція передавати назву сценарію посередині параметрів. Припустимо, ви хочете запустити lang -f <thecriptname> other-arg, а потім решту аргументів. З цим виправленим словом envце робиться так:

#!/usr/bin/env :lang:-f:{}:other-arg

Найлівіше поле, що еквівалентно {} , замінюється першим аргументом, що слідує, який під викликом хеш-вибуху є іменем сценарію. Потім цей аргумент видаляється.

Ось, other-arg може бути щось обробленеlang сценарієм або, можливо, щось оброблене.

Щоб краще зрозуміти, дивіться численні echo тести у патчі.

Я вибрав :символ, оскільки це існуючий роздільник, який використовується в PATHсистемах POSIX. Так envробить PATHпошук, це зникаюче навряд чи буде використовуватися для програми, ім'я якої містить двокрапку. {}Маркер походить від findутиліти, яка використовує його для позначення вставки шляху в -execкомандному рядку.


1
Для тих, хто читає це та відчуває надію, патч був відмовлений .
Алекс Міллер,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.