Dia
Dia

Reputation: 47

Running shell command from python script with \n

I am trying to run the shell command

echo -e 'FROM busybox\nRUN echo "hello world"' | docker build -t myimage:latest -

from jupyter notebook using subprocesses

I have tried the code

p = subprocess.Popen('''echo -e 'FROM busybox\nRUN echo "hello world"' | docker build -t myimage:latest - ''', shell=True)
p.communicate()

and some iterations with run() or call(), but everytime the output is

-e 'FROM busybox

It seems that the new line character \n causes the problem. Any ideas to solve the problem?

Upvotes: 2

Views: 359

Answers (1)

tripleee
tripleee

Reputation: 189749

The \n gets parsed by Python into a literal newline. You can avoid that by using a raw string instead,

p = subprocess.run(
    r'''echo -e 'FROM busybox\nRUN echo "hello world"' | docker build -t myimage:latest - ''',
    shell=True, check=True)

but I would recommend running a single process and passing in the output from Python; this also avoids a shell, which is generally desirable.

p = subprocess.run(['docker', 'build', '-t', 'myimage:latest', '-'],
    input='FROM busybox\nRUN echo "hello world"',
    text=True, check=True)

Notice also how we prefer subprocess.run() over the more primitive subprocess.Popen(); as suggested in the documentation, you want to avoid this low-level function whenever you can. With check=True we also take care to propagate any subprocess errors up to the Python parent process.

As an aside, printf is both more versatile and more portable than echo -e; I would generally recommend you to avoid echo -e altogether.

This ideone demo with nl instead of docker build demonstrates the variations, and coincidentally proves why you want to avoid echo -e even if your login shell is e.g. Bash (in which case you'd think it should be supported; but subprocess doesn't use your login shell).

Upvotes: 4

Related Questions