Выполнение многострочных операторов Python в однострочной командной строке
Я использую Python с -c
для выполнения однострочного цикла, т. е.:
$ python -c "for r in range(10): print 'rob'"
Это прекрасно работает. Однако, если я импортирую модуль перед циклом for, я получаю синтаксическую ошибку:
$ python -c "import sys; for r in range(10): print 'rob'"
File "<string>", line 1
import sys; for r in range(10): print 'rob'
^
SyntaxError: invalid syntax
есть идеи, как это можно исправить?
для меня важно иметь это как однострочный, чтобы я мог включить его в Makefile.
17 ответов
вы могли бы сделать
echo -e "import sys\nfor r in range(10): print 'rob'" | python
или без труб:
python -c "exec(\"import sys\nfor r in range(10): print 'rob'\")"
или
(echo "import sys" ; echo "for r in range(10): print 'rob'") | python
или @ответ SilentGhost / @Crast это
этот стиль также можно использовать в makefiles (и на самом деле он используется довольно часто).
python - <<EOF
import sys
for r in range(3): print 'rob'
EOF
или
python - <<-EOF
import sys
for r in range(3): print 'rob'
EOF
в последнем случае ведущий вкладка символы также удалены (и некоторые структурированные перспективы могут быть достигнуты)
вместо EOF может стоять любое маркерное слово, не появляющееся в документе here в начале строки (см. Также здесь документы на странице bash или здесь).
проблема на самом деле не с оператором import, это с чем-либо, находящимся перед циклом for. Или, более конкретно, все, что появляется перед встроенным блоком.
например, все работает:
python -c "import sys; print 'rob'"
python -c "import sys; sys.stdout.write('rob\n')"
если бы импорт, являющийся заявлением, был проблемой, это сработало бы, но это не так:
python -c "__import__('sys'); for r in range(10): print 'rob'"
для вашего самого основного примера вы можете переписать его следующим образом:
python -c "import sys; map(lambda x: sys.stdout.write('rob%d\n' % x), range(10))"
однако lambdas может выполнять только выражения, а не операторы или несколько операторов, поэтому вы все равно не сможете сделать то, что хотите сделать. Однако между выражениями генератора, пониманием списка, lambdas, sys.стандартный вывод.напишите," карта " встроенный, и некоторые творческие строки интерполяции, вы можете сделать некоторые мощные однострочные.
вопрос в том, как далеко вы хотите зайти, и в какой момент не лучше написать небольшой .py
файл, который ваш makefile выполняет вместо этого?
- Чтобы этот ответ работал с Python 3.x также, print
называется функции: в 3.x,только print('foo')
работает, тогда как 2.х также принимает print 'foo'
.
- Для кросс-платформенной перспективы, которая включает в себя окна см. полезный ответ kxr.
на bash
, ksh
или zsh
:
использовать ANSI C-цитируемая строка ($'...'
), что позволяет использовать \n
чтобы представить новые строки, которые расширяются до фактических новых строк, прежде чем строка передается в python
:
python -c $'import sys\nfor r in range(10): print("rob")'
Примечание \n
между import
и for
операторы для выполнения разрыва строки.
до pass shell-значения переменных для такой команды безопаснее всего использовать аргументы и sys.argv
внутри скрипта Python :
name='rob' # value to pass to the Python script
python -c $'import sys\nfor r in range(10): print(sys.argv[1])' "$name"
см. ниже для обсуждения плюсов и минусов использования (escape sequence-preprocessed)двойные кавычки командную строку с встроенный Shell-переменной-ссылки.
безопасно работать с $'...'
строки:
-
двойной
\
инстансы оригинал исходный код.-
\<char>
последовательностей - таких, как\n
в этом случае, но и обычные подозреваемые, такие как\t
,\r
,\b
- расширяются$'...'
(см.man printf
для поддерживаемых убегает)
-
- побег
'
экземпляров\'
.
если вы должны оставаться POSIX-совместимыми:
использовать printf
С команду:
python -c "$(printf %b 'import sys\nfor r in range(10): print("rob")')"
безопасно работать с этим типом строка:
-
двойной
\
инстансы оригинал исходный код.-
\<char>
последовательностей - таких, как\n
в этом случае, но и обычные подозреваемые, такие как\t
,\r
,\b
- расширяютсяprintf
(см.man printf
для поддерживаемых escape-последовательностей).
-
-
передать одинарные кавычки строка
printf %b
и побег встроенный одинарные кавычки'\''
(sic).-
использование одинарных кавычек защищает содержимое строки от интерпретации shell.
-
что сказано, ибо короче скрипты Python (как в этом случае) вы можете использовать строку с двойными кавычками для включения shell значения переменных в ваших скриптах-пока вы знаете о связанных подводных камнях (см. Следующий пункт); например, оболочка расширяется
$HOME
в домашний каталог текущего пользователя. в следующей команде:python -c "$(printf %b "import sys\nfor r in range(10): print('rob is $HOME')")"
-
однако обычно предпочтительным подходом является передача значений из оболочки через аргументы, и доступ к ним через
sys.argv
в Python; эквивалент приведенной выше команды:python -c "$(printf %b 'import sys\nfor r in range(10): print("rob is " + sys.argv[1])')" "$HOME"
-
-
при использовании двойные кавычки строк больше удобно - он позволяет использовать встроенные одинарные кавычки без эскапады и встроенные двойные кавычки как
\"
- это строка подлежит толкованию shell, что может быть или не быть намерением;$
и`
символы в исходном коде, которые не предназначены для оболочки может вызвать синтаксическую ошибку или неожиданно изменить строку.- кроме того, оболочки собственный
\
обработка в строках с двойными кавычками может помешать; например, получить питон произвести прямом выходеro\b
, вам необходимо пройтиro\b
к нему; с'...'
строка оболочки и два раза\
экземпляров, мы получаем:python -c "$(printf %b 'import sys\nprint("ro\\bs")')" # ok: 'ro\bs'
Напротив, это делает не работы с"..."
строка оболочки:python -c "$(printf %b "import sys\nprint('ro\\bs')")" # !! INCORRECT: 'rs'
Оболочка интерпретирует и"\b"
и"\b"
как литерал\b
, требуя огромное количество дополнительных\
случаях для достижения желаемого эффекта:python -c "$(printf %b "import sys\nprint('ro\\\\bs')")"
- кроме того, оболочки собственный
-
до передать код через stdin
, а не -c
:
Примечание: я фокусируюсь на одинон-лайн решения; xorho ответ показывает, как использовать многострочный здесь-документ - обязательно цитата разделитель, однако; например, <<'EOF'
, если вы явно не хотите, чтобы оболочка расширяла строку спереди (которая поставляется с оговорками, указанными выше).
на bash
, ksh
или zsh
:
сочетают в себе ANSI C-цитируемая строка ($'...'
) С строка (<<<...
):
python - <<<$'import sys\nfor r in range(10): print("rob")'
-
говорит python
однозначно читать из stdin (что он делает по умолчанию).
-
является необязательным в данном случае, но если вы также хотите пройти аргументы для скриптов вам нужно это, чтобы устранить неоднозначность аргумента из имени файла скрипта:
python - 'rob' <<<$'import sys\nfor r in range(10): print(sys.argv[1])'
если вы должны оставаться POSIX-совместимыми:
использовать printf
как и выше, но струбопровод чтобы передать его выход через stdin:
printf %b 'import sys\nfor r in range(10): print("rob")' | python
с аргументом:
printf %b 'import sys\nfor r in range(10): print(sys.argv[1])' | python - 'rob'
просто используйте return и введите его в следующей строке:
user@host:~$ python -c "import sys
> for r in range(10): print 'rob'"
rob
rob
...
есть идеи, как это можно исправить?
ваша проблема создается тем, что операторы Python, разделенные ;
, разрешены только "небольшие утверждения", которые являются все однострочными. Из файла грамматики в Python docs:
stmt: simple_stmt | compound_stmt simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt)
составные операторы не могут быть включены в одну строку с другими операторами через точки с запятой - поэтому это делается с помощью -c
флаг становится очень неудобный.
при демонстрации Python в среде оболочки bash я считаю очень полезным включать составные операторы. Единственный простой способ сделать это с помощью heredocs.
Heredocs
использовать помощи heredoc (создано с помощью <<
) и в Python опция интерфейса командной строки, -
:
$ python - <<-"EOF"
import sys # 1 tab indent
for r in range(10): # 1 tab indent
print('rob') # 1 tab indent and 4 spaces
EOF
добавлять -
после <<
(the <<-
) позволяет использовать вкладки в отступ (Stackoverflow преобразует вкладки в пробелы, поэтому я отступил 8 пробелов, чтобы подчеркнуть это). Ведущие вкладки будут удалены.
вы можете сделать это без вкладок, просто <<
:
$ python - << "EOF"
import sys
for r in range(10):
print('rob')
EOF
поставив кавычки EOF
предупреждает параметр и арифметические расширения. Это делает heredoc более надежным.
критика принятого ответа (и другие)
это не очень читабельно:
echo -e "import sys\nfor r in range(10): print 'rob'" | python
не очень читаемый и дополнительно сложный для отладки в случае ошибки:
python -c "exec(\"import sys\nfor r in range(10): print 'rob'\")"
возможно, немного более читаемый, но все же довольно уродливый:
(echo "import sys" ; echo "for r in range(10): print 'rob'") | python
у вас будет плохое время, если у вас есть "
в вашем python:
$ python -c "import sys > for r in range(10): print 'rob'"
не злоупотребляйте map
или Перечислите понимания, чтобы получить for-loops:
python -c "import sys; map(lambda x: sys.stdout.write('rob%d\n' % x), range(10))"
это все грустно и плохо. Не делайте этого.
проблема не в import
заявление. Проблема в том, что операторы потока управления не работают в команде python. Заменить import
заявление с любым другим заявлением, и вы увидите ту же проблему.
подумайте об этом: python не может встроить все. Он использует отступ для группировки control-flow.
Если ваша система Posix.2 совместимый он должен поставлять printf
утилиты:
$ printf "print 'zap'\nfor r in range(3): print 'rob'" | python
zap
rob
rob
rob
$ python2.6 -c "import sys; [sys.stdout.write('rob\n') for r in range(10)]"
работает нормально. Используйте " [ ]", чтобы встроить цикл for.
(ответили 23 ноября 10 в 19:48) Я не очень большой Pythoner-но я нашел этот синтаксис однажды, забыл, откуда, поэтому я думал, что документирую его:
если вы используете sys.stdout.write
вместо print
(разница в том, sys.stdout.write
принимает аргументы как функцию, в скобках-тогда как print
не), то для одного лайнера вы можете уйти с инвертированием порядка команды и for
, снятии с запятой, и вшита команды в квадратных скобках, например:
python -c "import sys; [sys.stdout.write('rob\n') for r in range(10)]"
понятия не имею, как этот синтаксис будет называться в Python :)
надеюсь, это поможет,
Ура!
(правка Вт апрель 9 20:57:30 2013) Ну, я думаю, что наконец-то нашел, о чем эти квадратные скобки в однострочных строках; они являются "пониманием списка" (по-видимому); сначала обратите внимание на это в Python 2.7:
$ STR=abc
$ echo $STR | python -c "import sys,re; a=(sys.stdout.write(line) for line in sys.stdin); print a"
<generator object <genexpr> at 0xb771461c>
Итак, команда в круглых скобках / скобках рассматривается как "объект-генератор"; если мы" переберем " его, вызвав next()
- тогда будет выполнена команда внутри круглой скобки (обратите внимание на " abc " в выходных данных):
$ echo $STR | python -c "import sys,re; a=(sys.stdout.write(line) for line in sys.stdin); a.next() ; print a"
abc
<generator object <genexpr> at 0xb777b734>
если мы теперь используем квадратные скобки-обратите внимание, что нам не нужно вызывать next()
чтобы команда выполнялась, она выполняется сразу после назначения; однако более поздняя проверка показывает, что a
is None
:
$ echo $STR | python -c "import sys,re; a=[sys.stdout.write(line) for line in sys.stdin]; print a"
abc
[None]
это не оставляет много информации для поиска, для площади скобки case-но я наткнулся на эту страницу, которая, я думаю, объясняет:
Python Советы И Рекомендации – Первое Издание - Python Учебники | Мечта.Внутри.Код:
если вы помните, стандартный формат генератора одной строки-это своего рода одна строка " для " петли внутри скобок. Это приведет к созданию "одноразового" итерируемого объекта, который вы можете перебирать только в одном направлении и который вы не можете повторно использовать, как только достигнете конца.
"понимание списка" выглядит почти так же, как обычный однострочный генератор, за исключением того, что регулярные скобки-() - заменяются квадратными скобками - []. Главное преимущество алистского понимания заключается в том, что создается "список", а не "однократный" итерационный объект, так что вы можете ходить по нему взад и вперед, добавлять элементы, сортировать и т. д.
и действительно, это список - это просто его первый элемент становится none, как только он исполнено:
$ echo $STR | python -c "import sys,re; print [sys.stdout.write(line) for line in sys.stdin].__class__"
abc
<type 'list'>
$ echo $STR | python -c "import sys,re; print [sys.stdout.write(line) for line in sys.stdin][0]"
abc
None
список понимания в противном случае документированы в 5. Структуры Данных: 5.1.4. Список постижений-Python v2.7.4 документация как "понимание списка обеспечивает краткий способ создания списков"; предположительно, именно здесь ограниченная" исполняемость " списков вступает в игру в однострочных.
ну, надеюсь, я не слишком ошибаюсь здесь ...
EDIT2: и вот однострочная командная строка с двумя не вложенными for-loops; оба заключены в квадратные скобки "понимание списка":
$ echo $STR | python -c "import sys,re; a=[sys.stdout.write(line) for line in sys.stdin]; b=[sys.stdout.write(str(x)) for x in range(2)] ; print a ; print b"
abc
01[None]
[None, None]
обратите внимание, что второй "список"b
теперь имеет два элемента, так как его цикл for явно выполняется дважды; однако результат sys.stdout.write()
в обоих случаях был (видимо) None
.
этот вариант наиболее переносим для размещения многострочных скриптов в командной строке на Windows и *nix, py2 / 3, Без каналов:
python -c "exec(\"import sys \nfor r in range(10): print('rob') \")"
(ни один из других примеров, увиденных здесь до сих пор, не сделал этого)
аккуратный на Windows:
python -c exec"""import sys \nfor r in range(10): print 'rob' """
python -c exec("""import sys \nfor r in range(10): print('rob') """)
аккуратный на баш/ * Никс:
python -c $'import sys \nfor r in range(10): print("rob")'
эта функция превращает любой многострочный скрипт в портативный command-one-liner:
def py2cmdline(script):
exs = 'exec(%r)' % re.sub('\r\n|\r', '\n', script.rstrip())
print('python -c "%s"' % exs.replace('"', r'\"'))
использование:
>>> py2cmdline(getcliptext())
python -c "exec('print \'AA\tA\'\ntry:\n for i in 1, 2, 3:\n print i / 0\nexcept:\n print \"\"\"longer\nmessage\"\"\"')"
вход было:
print 'AA A'
try:
for i in 1, 2, 3:
print i / 0
except:
print """longer
message"""
single/double quotes
и backslash
везде:
$ python -c 'exec("import sys\nfor i in range(10): print \"bob\"")'
лучше:
$ python -c '
> import sys
> for i in range(10):
> print "bob"
> '
этот скрипт предоставляет Perl-подобный интерфейс командной строки:
Pyliner-скрипт для запуска произвольного кода Python в командной строке (рецепт Python)
есть еще один вариант, sys.стандартный вывод.write возвращает None, которые держат список пустым
cat somefile.log|python -c "import sys;[line for line in sys.stdin if sys.stdout.write(line*2)]"
Я написал простую веб-страницу для этого. Вы можете вставить туда свой многострочный код, и он преобразуется в рабочий однострочный оператор.
Если вы не хотите касаться stdin и имитировать, как если бы вы прошли "python cmdfile.py", вы можете сделать следующее из оболочки bash:
$ python <(printf "word=raw_input('Enter word: ')\nimport sys\nfor i in range(5):\n print(word)")
Как вы можете видеть, он позволяет использовать stdin для чтения входных данных. Внутри оболочки создается временный файл для содержимого команды ввода.
когда мне нужно было это сделать, я использую
python -c "$(echo -e "import sys\nsys.stdout.write('Hello World!\\n')")"
Примечание тройной слеш в строку в sys.стандартный вывод.письменное заявление.