Python2.7 – 使用subprocess执行shell命令并将输出用于其他操作

huangapple go评论82阅读模式
英文:

Python2.7 - Execute shell command with subprocess and use output for the other

问题

我尝试在一个Pod中执行一些命令,但它没有生效。你有什么建议?

import subprocess

p = subprocess.Popen('kubectl get pods -o=custom-columns=NAME:.metadata.name | grep -i nottepod', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
    print line,

# 这里的line = Pod的确切名称。在这之后不起作用。它不能登录到Pod中。

p2 = subprocess.Popen("kubectl exec -it" + $(line) + "-- bash", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

p3 = subprocess.Popen("ls -lrth", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line2 in p3.stdout.readlines():
    print line2,

retval = p3.wait()

我期望在p2步骤中进入Pod后运行一些命令。

我真正尝试的是首先获取Pod的名称(p1),然后使用exec命令登录到Pod中(p2),这就是我需要p1输出的原因。在登录到Pod后,我还需要运行一些命令(p3等),这是我的主要目的。在下面,你可以看到当我手动运行它们时发生了什么。

[abc@master ~]$ kubectl get pods -o=custom-columns=NAME:.metadata.name | grep -i nottepod
nottepod-xyz

[abc@master ~]$ kubectl exec -it nottepod-xyz -- bash
Defaulted container "notte" out of: notte, key
[root@master -notte ]# ls -lrth

total 216M

drwxr-xr-x  2 root root     6 Jul  6  2022 Cache

-rwxr-xr-x  3 1037 users  111 Dec 26 16:51 start.sh

-rwxr-xr-x  3 1037 users  291 Dec 26 16:51 rataten.sh
英文:

I'm trying to execute some command in a pod but it's not working. What could be your suggessing?

import subprocess

p = subprocess.Popen('kubectl get pods -o=custom-columns=NAME:.metadata.name | grep -i nottepod' , shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
    print line,

#Here the line = exact name of the pod. After here not working. it's not login to the pods

p2 = subprocess.Popen("kubectl exec -it' +$(line)+ '-- bash'" , shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

p3 = subprocess.Popen("ls -lrth" , shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line2 in p3.stdout.readlines():
    print line2,

retval = p3.wait()

I expect to run a couple of command after get in the pod with p2 step.

What I really try is, first, get the pods name(p1), login to the pod with exec command(p2) that's why I need p1 output to use in it. After I'm login to the pod, I also need to run some commands (p3..etc) That's my main purpose. Below you can see what's happening when I run them manually.

> [abc@master ~]$ kubectl get pods -o=custom-columns=NAME:.metadata.name | grep -i nottepod
>
> nottepod-xyz
>
> [abc@master ~]$
>
> [abc@master ~]$ kubectl exec -it nottepod-xyz -- bash
>
> Defaulted container "notte" out of: notte, key
>
> [root@master -notte ]# ls -lrth
>
> [root@master -notte ]# ls -lrth
>
> total 216M
>
> drwxr-xr-x 2 root root 6 Jul 6 2022 Cache
>
> -rwxr-xr-x 3 1037 users 111 Dec 26 16:51 start.sh
>
> -rwxr-xr-x 3 1037 users 291 Dec 26 16:51 rataten.sh

答案1

得分: 2

If you merely meant to interpolate the Python variable named line, you probably want

p2 = subprocess.check_output(
    ["kubectl", "exec", "-it", line, "--",
     "bash", "-c", "couple of commands; more commands"])

Notice how this also avoids the overhead and security implications of shell=True

Generally, avoid Popen always when you can.

If you really want the exec bash to accept commands interactively, you do need Popen, and need to submit those commands as standard input to the interactive shell. But this is probably best avoided if you can.

Here is a refactoring to use check_output throughout, and avoid shell=True everywhere.

import subprocess

pods = subprocess.check_output(['kubectl', 'get', 'pods', '-o=custom-columns=NAME:.metadata.name'])
nottepod = [pod for pod in pods.splitlines() if 'nottepod' in pod.lower()]
assert len(nottepod) == 1
nottepod = pod[0]
print(nottepod,)

lsout = subprocess.check_output(
    ['kubectl', 'exec', '-it', nottepod, '--',
     'bash', '-c', 'ls -lrth'])
for line in lsout.splitlines():
    print(line,)

Splitting the output into lines only then to print them each separately is obviously silly, but I imagine you might want to do something more useful with each output line ultimately. If not, simply print(lsout,) in one go for simplicity.

英文:

If you merely meant to interpolate the Python variable named line, you probably want

p2 = subprocess.check_output(
    ["kubectl", "exec", "-it", line, "--",
     "bash", "-c", "couple of commands; more commands"])

Notice how this also avoids the overhead and security implications of shell=True

Generally, avoid Popen always when you can.

If you really want the exec bash to accept commands interactively, you do need Popen, and need to submit those commands as standard input to the interactive shell. But this is probably best avoided if you can.

Here is a refactoring to use check_output throughout, and avoid shell=True everywhere.

import subprocess

pods = subprocess.check_output(['kubectl', 'get', 'pods', '-o=custom-columns=NAME:.metadata.name'])
nottepod = [pod for pod in pods.splitlines() if 'nottepod' in pod.lower()]
assert len(nottepod) == 1
nottepod = pod[0]
print(nottepod,)

lsout = subprocess.check_output(
    ['kubectl', 'exec', '-it', nottepod, '--',
     'bash', '-c', 'ls -lrth'])
for line in lsout.splitlines():
    print(line,)

Splitting the output into lines only then to print them each separately is obviously silly, but I imagine you might want to do something more useful with each output line ultimately. If not, simply print(lsout,) in one go for simplicity.


(The following was part of my original answer before you clarified your question. I have moved it down here in case there are future visitors with a different problem.)

The expression $(line) is wrong, but we can't really guess what you hope for it to mean.

If line is a command you want to run as a command substitution, the syntax is correct as such, but you will probably want to remove the single quotes and the plus marks around it, and maybe add double quotes. (This seems implausible, but I'll mention it anyway.)

# XXX FIXME: implausible but still possible
p2 = subprocess.check_output(
    'kubectl exec -it "$(line)" -- bash',
    shell=True)

If you wanted to use the value of the Python variable line as the command to run, that's

# XXX FIXME: also implausible but still possible
p2 = subprocess.check_output(
    'kubectl exec -it "$(' + shlex.quote(line) + ')" -- bash',
    shell=True)

It's not clear what you wanted to do with the output from the subprocess. You might want to use check_call if you don't care about the output, but then you probably want stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL if you don't want them displayed to the user.

huangapple
  • 本文由 发表于 2023年1月9日 19:46:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/75056821.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定