6

I am creating small console script in python, and I will like to put cowsay command in it, but cow says name of the variable, where the string is, not the string inside the variable. How I can get the cow to say string inside the variable?

if (command == 'cow'):
    word = raw_input('What does the cow say?  ')
    os.system('cowsay word')

2 Answers2

9

lazy solution is to simply concatenate the word:

>>> import os
>>> word="moo"
>>> os.system('cowsay ' + word)
 _____ 
< moo >
 ----- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
0

BUT you should not do this. What if the user inputs moo; rm -rf /? guess what will happen. Also, word="$(cat /etc/passwd)" and word="$aliases" or words with backticks will yield non-expected results.

You should use the Subprocess module, which takes care of escaping shell args and constructing the call:

>>> import subprocess
>>> subprocess.Popen(['cowsay', word])
<subprocess.Popen object at 0x7fe8c7656c18>
>>>  _____ 
< moo >
 ----- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

Use .communicate() for simple invocations, as described in the docs or as in the example below. And now you don't have to worry about injections:

>>> word="$(cat /etc/passwd)"
>>> stdout, stderr = subprocess.Popen(
                     ['cowsay', word]).communicate()
 ____________________ 
< $(cat /etc/passwd) >
 -------------------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
ch3ka
  • 11,792
  • 4
  • 31
  • 28
  • Thanks, but what does the "" line do? – Aleksi Väisänen Nov 25 '14 at 14:21
  • that's just the subprocess object returned by `Popen`. You can bind it to a variable and communicate with it. – ch3ka Nov 25 '14 at 14:21
  • So I bind it into variable and I can communicate with it how? What I can do when I communicate with it? (And yes I am newbie on programming) – Aleksi Väisänen Nov 25 '14 at 14:25
  • take a look at the docs: https://docs.python.org/2/library/subprocess.html You can send data to it's stdin, for example. – ch3ka Nov 25 '14 at 14:27
  • You should prefer `subprocess.run()` and friends over bare `subprocess.Popen()` (`subprocess.check_call()` etc in Python 2). The basic `Popen` constructor is useful if you need to manage the process yourself, but you don't want to when you don't have to. – tripleee Oct 12 '21 at 07:34
6

You could use format to construct the string

os.system('cowsay {}'.format(word))

Or simple string concatenation

os.system('cowsay ' + word)

But I prefer the former, especially if the string get more complicated.

Cory Kramer
  • 114,268
  • 16
  • 167
  • 218