10

Why do I receive a syntax error for the following one-liner Python code?

python -c 'import re; if True: print "HELLO";'
  File "<string>", line 1
    import re; if True: print "HELLO";
                ^
SyntaxError: invalid syntax

The following code works just fine:

python -c 'if True: print "HELLO";'

How can I change my one line to execute my intended script on a single line from the command line?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
AffluentOwl
  • 3,337
  • 5
  • 22
  • 32
  • 1
    Not an answer: Why do you want to put stuff into one line? What is the benefit, why is it better than a real script? – guettli Apr 25 '14 at 18:46
  • The benefit is that I don't have any file write permissions on the system I am running this on. Also, I commonly want to copy and paste one liners to friends, and this makes it so they don't have to create files and grant those execute permissions. – AffluentOwl Apr 25 '14 at 18:57
  • 1
    see http://stackoverflow.com/questions/6167127/how-to-put-multiple-statements-in-one-line – a5hk Apr 25 '14 at 18:59
  • 1
    This looks like being a duplicate of this : http://stackoverflow.com/questions/2043453/executing-python-multi-line-statements-in-the-one-line-command-line At least, the link contains a lot of nice workarounds.. – slaadvak Apr 25 '14 at 19:00
  • @slaadvak I agree this is a duplicate of that question, but I like Rynants answer provided below better than the ones offered there. @ Ashkan That question answers why one liners cannot exist in a python file, but doesn't answer how to write one line python code on the command line, which is what I'm trying to do. – AffluentOwl Apr 25 '14 at 19:12
  • @AffluentOwl Actually, you just asked why you receive the SyntaxError, not how to work around it :) – dano Apr 25 '14 at 19:21
  • @dano True. I clarified this in a comment on another answer which was deleted. I just edited my question to update that I was interested in both why this is the case, and workarounds. – AffluentOwl Apr 25 '14 at 19:22
  • 1
    @AffluentOwl if you don't have write permission on the system, and you can connect to it by ssh you can use this `cat scripts/myscript.py | ssh localhost python` – guettli Apr 26 '14 at 18:04
  • @guettli Good to know. Unfortunately, in my case, I do not have SSH permissions. This is a locked down computer at work where I pretty much can only run Chrome. – AffluentOwl Apr 27 '14 at 18:20
  • If you really want to use re in python oneliners, pythonpy (https://github.com/Russell91/pythonpy) may be of interest to you: echo me2 | py -x 're.sub("me", "you", x)' => you2 – RussellStewart Sep 13 '14 at 06:27
  • @singular Also cool to know about, but unfortunately I cannot install anything on my work computer. – AffluentOwl Sep 27 '14 at 22:36

4 Answers4

12

One option to work around this limitation is to specify the command with the $'string' format using the newline escape sequence \n.

python -c $'import re\nif True: print "HELLO";'

Note: this is supported by shells, such as Bash and Z shell (zsh), but it is not valid POSIX Bourne shell (sh).

As mentioned by slaadvak, there are some other workarounds here: Executing Python multi-line statements in the one-line command-line

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rynant
  • 23,153
  • 5
  • 57
  • 71
6

The problem isn't with the import statement specifically. It’s that you have anything before a control flow statement. This won't work, either:

dan@dan:~> python -c 'a = "1234" ; if True: print "hi"'
  File "<string>", line 1
    a = "1234" ; if True: print "hi"
                  ^
SyntaxError: invalid syntax

According to the Python reference (7. Compound statements), ';' can only be used to combine "simple statements" together. In this case you're combining the simple statement import re, with if True:. if True isn't a simple statement, because it’s introducing flow control, and is therefore a compound statement. At least that's how I interpret the documentation.

Here's the full text from the Python reference:

Compound statements consist of one or more ‘clauses.’ A clause consists of a header and a ‘suite.’ The clause headers of a particular compound statement are all at the same indentation level. Each clause header begins with a uniquely identifying keyword and ends with a colon. A suite is a group of statements controlled by a clause. A suite can be one or more semicolon-separated simple statements on the same line as the header, following the header’s colon, or it can be one or more indented statements on subsequent lines

compound_stmt ::=  if_stmt
                   | while_stmt
                   | for_stmt
                   | try_stmt
                   | with_stmt
                   | funcdef
                   | classdef
                   | decorated
suite         ::=  stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
statement     ::=  stmt_list NEWLINE | compound_stmt
stmt_list     ::=  simple_stmt (";" simple_stmt)* [";"]
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dano
  • 91,354
  • 19
  • 222
  • 219
3

You can embed newlines directly in the argument.

python -c 'import re
> if True:
>   print "HELLO"
> '
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
chepner
  • 497,756
  • 71
  • 530
  • 681
  • How do you do this? Is there some special keyboard combination? Because just pressing enter executes the line without embedding a new newline. – AffluentOwl Apr 25 '14 at 19:20
  • 2
    If you are using any POSIX-compliant shell, pressing Enter in the middle of a quoted string should not execute the command (unless, for example, you've change the default `readline` binding for the Enter key). – chepner Apr 25 '14 at 19:21
  • I'm using Ubuntu. Is that perhaps a bash shell instead of a POSIX-compliant shell? – AffluentOwl Apr 25 '14 at 19:27
  • 1
    `bash` is POSIX-compliant in this sense. – chepner Apr 25 '14 at 19:33
  • Turns out this only applies if you type it from beginning to end, without having to use the arrow keys to make any changes. This is less than desirable, but still good to know. Thanks. – AffluentOwl Apr 25 '14 at 19:36
2

Why do I receive a syntax error for the following one-liner Python code?

Python grammar might forbid small_stmt ';' compound_stmt. The -c argument is probably is interpreted as file_input:

fileinput: (NEWLINE | stmt)* ENDMARKER
stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: import_stmt <in this case>
compound_stmt: if_stmt <in this case>

Note: there is a newline at the end of simple_stmt. if_stmt is not small_stmt; it can't follow another small_stmt after ';'. A newline is necessary to introduce compound_stmt after small_stmt.

It is not an issue because Bash allows multiline arguments. Just don't close the opening single quote until you are done, e.g.:

python -c '
> import re
> if 1:
>   print(1)
> '

1

Note: >s are printed by the shell itself here. It is not entered by hand.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jfs
  • 399,953
  • 195
  • 994
  • 1,670