3

Say I want to print 1 + 1 on stdout (i.e. one-liner coding).

With awk I could do it simply with:

$ echo | awk '{print 1+1}'
2

How to do this with python?

nobody
  • 19,814
  • 17
  • 56
  • 77
cregox
  • 17,674
  • 15
  • 85
  • 116
  • You could also use [`eval("print 1+1")`](https://docs.python.org/2/library/functions.html#eval) to evaluate string expressions. – Mr. Polywhirl Sep 15 '14 at 21:41
  • 1
    With `awk` you don't need `echo`. Use `BEGIN`. `awk 'BEGIN{print 1+1}'` – jaypal singh Sep 15 '14 at 21:46
  • `awk 'END{print 1+1}' < /dev/null` would be more efficient. – chepner Sep 15 '14 at 21:47
  • 1
    Note that Python isn't nearly as useful for one-liners as `awk`… but it's a lot more useful for, e.g., 5-liners, so you tend to see it used with HEREdoc scripts more than with inline scripts. (But you _can_ use it for inline scripts, as IfLoop's answer shows.) – abarnert Sep 15 '14 at 21:48
  • 1
    @chepner Can you please elaborate on why `END` is more efficient than `BEGIN`? AFAIK both runs exactly once, with former after the input has been read and former before the input has been read. – jaypal singh Sep 15 '14 at 21:54
  • 1
    @jaypal It isn't; I posted my comment before I saw yours appear, and just happened to use `END` instead of `BEGIN`. "More efficient" just refers to ignoring the (empty) standard input in place of starting a second process to provide input that is to be ignored anyway, not the choice between `BEGIN` and `END`. – chepner Sep 15 '14 at 21:55
  • @abarnert that was precisely the core of my question. Is there a way to make Python to become as useful as `awk` for one-liners? – cregox Sep 16 '14 at 00:18
  • 1
    @Cawas: Python is explicitly designed to value readability over brevity and explicitness over implicitness. There are limits to what you can cram onto one line; things that would be syntax in awk (or sed or perl) are vocabulary in Python, possibly not even built-in; there is very little magic for things like stdin or command-line args; etc. So no, Python will never be as useful as awk for one-liners. – abarnert Sep 16 '14 at 00:26
  • 1
    @Cawas: Also if you ask most of the core devs, they'll tell you that if you know the awk or sed or grep one-liner for what you're trying to write, there's no reason you shouldn't use awk or sed or grep; Python doesn't have to be the language for everything. But if you can't remember the details of the syntax… well, that's exactly why Python is designed to be explicit and readable, and if that means you have to write it in 3 lines to remember how to write it, that's not a problem. – abarnert Sep 16 '14 at 00:28
  • @abarnert And if you would add all that as an answer along with `-c` it would be just perfect! Or maybe give an editorial to IfLoop, I dunno. – cregox Sep 16 '14 at 03:38
  • @Cawas: OK, done. But I think you should leave ifLoop's answer as the accepted one because it directly answers your question, with all the relevant details; mine just offers another perspective that is important for many use cases but isn't actually relevant to `print 1+1`. – abarnert Sep 16 '14 at 18:16
  • @abarnert look at the title. `print 1+1` was just an example. IfLoop answered my question perfectly, but maybe he didn't catch its intent as good as you did and he certainly didn't bring the great complement you did. Yours also explain all other different answers - people didn't want me to use Python instead of awk for a good reason. – cregox Sep 17 '14 at 08:52

5 Answers5

7

you are looking for -c:

$ python -c 'print 1 + 1'
2
SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • 1
    The `echo hello |` is unnecessary here. `awk` only needs it because it operates on lines of input. – jwodder Sep 15 '14 at 21:44
  • @bgbg: Python doesn't do any magic with stdin; you have to explicitly call `input`, or loop over something like `sys.stdin` or `fileinput.input()`, if you want that. – abarnert Sep 15 '14 at 21:49
  • @bgbg `awk` implicitly loops over its standard input, so `BEGIN` and `END` are used to execute code before and after, respectively, the input is read. Python, conversely, ignores its standard input unless your code specifically reads from it. – chepner Sep 15 '14 at 21:49
  • Reason I changed the accepted answer: this resolves exactly my example, but in reality it doesn't answer my question "python as if it were awk". At first I though it would be this simple, but it isn't: http://stackoverflow.com/questions/2043453/executing-python-multi-line-statements-in-the-one-line-command-line – cregox Sep 17 '14 at 11:29
3

As ifLoop pointed out, what you're looking for here is -c.

But, as yo've discovered, python -c often isn't as useful as the corresponding awk (or sed or bash or perl or even ruby) for one-liners.

Python is explicitly designed to value readability over brevity and explicitness over implicitness (along with some correlated tradeoffs, like vocabulary over syntax, as little magic as possible, etc.). See the Zen of Python. There are intentional limits to what you can cram onto one line, and things like looping over stdin and/or command-line args have to be done explicitly with, e.g., sys.stdin and sys.argv, or fileinput.input().

That means that some very trivial scripts become less trivial to write in Python, but that's considered a good tradeoff for making even moderately non-trivial scripts easier to write, maintain, and understand.

The core developers understand this means you can't rewrite a lot of one-liners in Python. And if you asked them, most of them will ask why that's a problem at all.

If you know how to write something as a one-liner in a language like sed or awk, then you should be writing it as a one-liner in sed or awk. Those are perfectly good languages that are handy for all kinds of simple tasks, and there's no reason to avoid them just because Python is also a good language.

If you can't figure your way through the syntax to write that one-liner… well, it probably shouldn't be a one-liner. The only reason you want to try it in Python is that Python is generally easier to write and read, and the same reasons that's true are the same reasons Python won't let you write what you want without 3 lines. So just write the 3 lines. Python is great for that.

So, what you often really want is not -c, but a heredoc, or just a separate script that you run like any other program, or awk or perl instead of python.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • I'd argue a lot of people don't care for learning more and more languages. The biggest reason for my question is my brother who works with cisco and stuff, so he knows how to shell but he's no programmer, nor he wants to be. He just wants to learn how to program to simplify his life and, as such, Python has this much higher potential over `awk` or `sed` (sed isn't even a language)... Anyway, this should probably go on to a forum or maybe just to another question! I'll link either once I figure it out. :P – cregox Sep 17 '14 at 09:25
  • There you go: http://discuss.howtogeek.com/t/why-dont-we-have-an-one-liner-python/19528 – cregox Sep 17 '14 at 11:32
  • @Cawas: One of the strengths of something like `awk` is that you can teach people to do simple things without making them realize they're learning programming… But yeah, I can see your point that it would be great if we had one language that was ideal for everything, or at least for everything non-professional-programmer types might want to do. Maybe build a shell on top of Python instead of making Python more usable from the shell? But I've seen people try to do that with C/Cint, emacs-lisp, Tcl, etc., and it generally hasn't been pretty… Anyway, I'll check the forum out when I get a chance… – abarnert Sep 17 '14 at 17:24
1

Inspired by the answer by IfLoop I wondered about the handy BEGIN and END blocks in awk. I have found the pawk module

    ls -l | awk 'BEGIN {c = 0} {c += $5} END {print c}'
    ls -l | pawk -s -B 'c = 0' -E 'c' 'c += int(f[4])'

Looks promising, but I have never tried this (yet)

Community
  • 1
  • 1
Boris Gorelik
  • 29,945
  • 39
  • 128
  • 170
  • That pawk looks interesting! I love Python, but I often find myself reverting to awk for little things because multi-line Python in the command line is rather tedious. – PM 2Ring Sep 15 '14 at 23:26
  • @PM2Ring: Reverting to awk for little things is fine. Or sed, grep, bash itself… maybe even perl in some cases (as long as you don't tell anyone). – abarnert Sep 16 '14 at 00:29
  • Sometimes, bash makes more sense than Python, but it can be very annoying, especially when handling filenames with spaces & other garbage in them. I frequently use grep, generally to do regex stuff on ls output, or to search my *.py files. Years ago, I wrote an HTML parser in awk (for very fixed format HTML), but I won't be doing that again in a hurry. :) When I was learning sed I wrote a sed script that increments integers, but it's not pretty. :) – PM 2Ring Sep 16 '14 at 00:52
0

if you're in the shell, the next would basic integer math

echo $((1+1))
echo $(( 100 / 5 ))

etc...

for floating point, yes, you should to use awk, or bc, or dc, or any other language what knows floating point math...

also, read this: https://stackoverflow.com/a/450853/632407

Community
  • 1
  • 1
clt60
  • 62,119
  • 17
  • 107
  • 194
0

Like SingleNegationElimination's answer recommend's, the -c flag is the right tool for the job.

Here are some examples using awk, ruby, and python:

echo foo bar baz | awk '{ split($0, arr, " "); print arr[NF] }'
baz
echo foo bar baz | ruby -e 'puts STDIN.read.chomp.split(" ")[-1]'
baz
echo foo bar baz | python -c 'import sys; print sys.stdin.read().rstrip().split(" ")[-1]'
baz
mbigras
  • 7,664
  • 11
  • 50
  • 111
  • so, are you also telling us that this is now working? http://stackoverflow.com/questions/2043453/executing-python-multi-line-statements-in-the-one-line-command-line – cregox Feb 14 '18 at 21:59