33

I'm trying to do the following:

output = run("ls -l backups")
for line in output.split("/n"):
    do_stuff(line)

Any way of having the stdout of ls sent to output?


To be more specific I'm using a CLI app called s3cmd which does something similar to ls, but with remote Amazon S3 buckets.

So a replacement for ls won't help unfortunately.


JCotton
  • 11,650
  • 5
  • 53
  • 59
RadiantHex
  • 24,907
  • 47
  • 148
  • 244

6 Answers6

28

Exactly what you are asking for should be happening. From the docs:

run will return the result of the remote program’s stdout as a single (likely multiline) string.

run(), and related commands like local() and sudo(), return an _AttributeString object that is just a wrapper around stdout with attribute access to additional information like failure/success booleans, stderr, the command run, etc. The result object also has a stdout attribute, which is just more explicit.

To troubleshoot, print type(output), output to be sure the response is what you expect. Examine output.failed and output.stderr. It could be the command isn't doing what you expect, there is no "backups" directory, etc.

JCotton
  • 11,650
  • 5
  • 53
  • 59
  • `... output = run(cmd) print 'command output: {}'.format(output.stdout) ...` – kip2 Jun 07 '17 at 15:56
  • you may have to strip some unicode characters: for instance, use `... .stdout.strip('\x00')` before conversion to int – Francois Sep 07 '18 at 15:46
17

Try as below using String IO

from fabric.api import *
from StringIO import StringIO

fh = StringIO()
run("ls -l backups", stdout=fh)

fh.seek(0)
for line in fh.readlines():
    do_stuff(line)
user1406490
  • 187
  • 3
15

In case you need to use run(), you can do it like this:

with settings(
    hide('warnings', 'running', 'stdout', 'stderr'),
    warn_only=True
):
    command = 'ls -l backups'
    output = run(command)
    for line in output.splitlines():
        do_stuff(line)

For local() there is a bit more simple solution:

command = 'ls -l backups'
output = local(command, capture=True)
for line in output.splitlines():
    do_stuff(line)

I hope it helps.

Evhz
  • 8,852
  • 9
  • 51
  • 69
  • this should be the accepted answer. the top solution contains all the fabric formatting (IP, fabric command, ...) – Simon Ninon Feb 04 '20 at 23:34
7

Try split using "\r\n":

output = run("ls -l backups")
output_stdout = output.stdout.split("\r\n")
J. Chomel
  • 8,193
  • 15
  • 41
  • 69
Itay Katz
  • 166
  • 2
  • 6
  • The solution I was looking for! Is there a good way to remove all the escape codes to save it into a variable (so not just using print) ? – Macindows Jan 09 '20 at 08:02
7

You can also use this if you are using the local() api, by setting the capture=True

@task
def login_ecr_docker():
    ecr_login = local("aws ecr get-login --region us-west-2", capture=True)
    docker_login = ecr_login.stdout
    status = local(docker_login, capture=True)
    print (status.stdout)
pitaside
  • 650
  • 10
  • 14
1

Just simply return it:

def output():
    return run("ls -l backups")
a = execute(output, host=hostname)
print a

a will be dictionary of results.

Bekzot Asimov
  • 431
  • 5
  • 10