python subprocess.run() wrongly parses command - python

I use python to execute the shell commands. The command call make with some extra flags:
version_info = r"CXXOPTS+='-DVERSION=" + r'\"' + args.version + r'\"' + r"'" + \
" -DSOFTWARE_FLAVOR=" + r'\"' + args.software_flavor + r'\"' + \
" -DSOFTWARE_DECORATOR=" + r'\"' + args.software_decorator + r'\"' + r"'"
where args is the arguments parsed by ArgumentParser from the command line that called this python script.
Then I execute:
command = f"make {version_info} all"
subprocess.run(command, shell=True, encoding="iso-8859-1", check=True)
It reports error: unknown output-sync type FTWARE_FLAVOR.
It seems it cannot recognize -DSOFTWARE_FLAVOR.
Then I tried to split this command line as follows:
version = r"CXXOPTS+='-DVERSION=" + r'\"' + args.version + r'\"' + r"'"
flavor = r"CXXOPTS+='-DSOFTWARE_FLAVOR=" + r'\"' + args.software_flavor + r'\"' + r"'"
.....
Then it works correctly.
What is the reason of this error?
Thank you in advance.

I think your life becomes simpler if you drop the shell=True and pass a list to subprocess.run, because this allows you to drop much of the elaborate quoting you're using to create your command line. For example:
from collections import namedtuple
version_info = (
f'CXXOPTS+=-DVERSION="{args.version}" '
f'-DSOFTWARE_FLAVOR="{args.software_flavor}" '
f'-DSOFTWARE_DECORATOR="{args.software_decorator}"'
)
command=['make', version_info, 'all']
subprocess.run(command)
If I have a Makefile that looks like this:
all:
echo CXXOPTS: "$(CXXOPTS)"
And I add some code to populate args:
import argparse
import subprocess
p = argparse.ArgumentParser()
p.add_argument('--version', default='1')
p.add_argument('--software-flavor', default='vanilla')
p.add_argument('--software-decorator', default='martha.stewaret')
args = p.parse_args()
version_info = (
f'CXXOPTS+=-DVERSION="{args.version}" -DSOFTWARE_FLAVOR="{args.software_flavor}" '
f'-DSOFTWARE_DECORATOR="{args.software_decorator}"'
)
command=['make', version_info, 'all']
subprocess.run(command)
Then I get as output:
echo CXXOPTS: -DVERSION="1" -DSOFTWARE_FLAVOR="vanilla" -DSOFTWARE_DECORATOR="martha.stewaret"
CXXOPTS: -DVERSION=1 -DSOFTWARE_FLAVOR=vanilla -DSOFTWARE_DECORATOR=martha.stewaret

Related

How to use session-manager-plugin command

I want to use session-manager-plugin in python code.
The code is written as follows
import boto3
from boto3.session import Session
import subprocess
AWS_REGION = "ap-northeast-1"
AWS_PROFILE = "default"
INSTANCE_ID = "i-XXXXX"
ssm = boto3.client('ssm')
response = ssm.start_session(
Target=INSTANCE_ID,
DocumentName='AWS-StartPortForwardingSession',
Parameters={
'portNumber': ['3389'],
'localPortNumber': ['13389'],
}
)
parameters = "{'DocumentName': 'AWS-StartPortForwardingSession', 'Target': "+INSTANCE_ID+", 'Parameters': {'portNumber': ['3389'], 'localPortNumber': ['13389']}}"
def start_aws_ssm_plugin(create_session_response, parameters, profile, region):
arg0 = '"' + 'session-manager-plugin' + '"'
arg1 = '"' + str(create_session_response).replace('\'', '\\"') + '"'
arg2 = region
arg3 = 'StartSession'
arg4 = profile
arg5 = '"' + str(parameters).replace('\'', '\\"') + '"'
arg6 = 'https://ssm.{region}.amazonaws.com'.format(region=region)
command = arg0 + ' ' + arg1 + ' ' + arg2 + ' ' + arg3 + ' ' + arg4 + ' ' + arg5 + ' ' + arg6
pid = subprocess.Popen(command).pid
return pid
start_aws_ssm_plugin(response, parameters, AWS_PROFILE, AWS_REGION)
But, the code gets an error.
panic: interface conversion: interface {} is nil, not string
goroutine 1 [running]:
github.com/aws/SSMCLI/src/sessionmanagerplugin/session.ValidateInputAndStartSession(0xc00010c000, 0x7, 0x8, 0x14c2380, 0xc000006018)
I wrote the code with reference to "https://stackoverflow.com/questions/65963897/how-do-i-use-the-results-of-an-ssm-port-forwarding-session-started-with-ruby/66043222#66043222"
If you have any information, please let me know.
Thank you
You seem to mess up quoting the two json arg strings. This works on Windows10:
import boto3
ssm = boto3.client('ssm')
instance_id = "i-XXXXX"
ssm_response = ssm.start_session(
Target=instance_id,
DocumentName='AWS-StartPortForwardingSession',
Parameters={"portNumber": ["8080"], "localPortNumber": ["9999"]}
)
cmd = [
'C:/Program Files/Amazon/SessionManagerPlugin/bin/session-manager-plugin.exe',
json.dumps(ssm_response),
'eu-central-1', # client region
'StartSession',
'default', # profile name from aws credentials/config files
json.dumps(dict(Target=instance_id)),
'https://ssm.eu-central-1.amazonaws.com' # endpoint for ssm service
]
subprocess.run(cmd)
The source https://github.com/aws/session-manager-plugin/blob/mainline/src/sessionmanagerplugin/session/session.go was helpful.
As I know you need call the start-session endpoint to get the streamurl, sessionid and token. Then call session-manager-plugin to forward tty.
https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_StartSession.html

Pipe character is messing up my pexpect command string

I have a string that I build then pass to pexpect:
command = "for i in `python /tmp/"+ cecUser + "_getSyslogs.py " + startString + " " + endString + " " + myDir + "`;do gzcat /emslogs/archive/" + myDir + "/$i | grep " + node + " | egrep -v \"" + filteredWords + "\" >> /tmp/" + syslogFile + ";done"
p.sendline(command)
If filteredWords = "No LMA address", the script runs fine.
If filteredWords = "No LMA address|CLISess", the script fails.
What am I missing? I tried to escape the | by preceding with \ and that didn't help. I actually tried a whole slew of different combinations and the script still fails. What is even odder is the logging output from p.logfile looks fine:
$ for i in `python /tmp/getSyslogs.py 20141227120000 20141228120000 local1`;do gzcat /emslogs/archive/local1/$i | grep ALPRGAGQPN2 | egrep -v "No LMA address|CLISess" >> /tmp/1419900585.83_ALPRGAGQPN2_syslogs.txt;done
If I cut'n'paste that line on the target machine, it works no problem. There is just something about the pipe in the egrep that is messing up when passed to p.sendline.

Python code to send command through command line

final="cacls " + "E:/" + "\"" + list1[2] + " " + list1[3] + "\"" + " /p " + str
os.system(final)
I am trying to set permission to a folder Using Python but while running this command , User input needs to be provided too i.e
it asks ARE YOU SURE(Y/N) and the user needs to enter "Y" or "N"
Is there any way to use python to send the user input "Y" along with the above code?
pro = subprocess.Popen(final,shell=True, stdin=subprocess.PIPE)
pro.communicate(bytes("Y\r\n",'utf-8'))
I have added the following code . The program exits without setting the permission.
http://jimmyg.org/blog/2009/working-with-python-subprocess.html#writing-to-standard-input
Try using the subprocess module
import subprocess
cmd = ["cacls", "E:/" + list1[2], list1[3], "/p", str]
pro = subprocess.Popen(final, stdin=subprocess.PIPE)
pro.communicate("y\r\n")
As a smart programmer, use PBS
Then, the code is:
from pbs import type as echo# Isn't it echo for Windows? If not, use the correct one
script = Command("/path/to/cacls ")
print script(echo("Y"), ("E:/" + "\"" + list1[2] + " " + list1[3] + "\"" + " /p " + str).split())

Usage of subprocess class in Python

final="cacls " + "E:/" + "\"" + list1[2] + " " + list1[3] + "\"" + " /p " + str
pro = subprocess.Popen(final,shell=True, stdin=subprocess.PIPE)
pro.communicate(bytes("Y\r\n",'utf-8'))
Trying to set permission to a folder Using Python but while running this command , User input needs to be provided too i.e
it asks ARE YOU SURE(Y/N) and the user needs to enter "Y" or "N"
The above code is not setting the permission.
This was the question i had asked before:
Python code to send command through command line
As a smart programmer, use PBS
Then, the code is:
from pbs import type as echo# Isn't it echo for Windows? If not, use the correct one
script = Command("/path/to/cacls ")
print script(echo("Y"), ("E:/" + "\"" + list1[2] + " " + list1[3] + "\"" + " /p " + str).split())

Pass python script output to another programs stdin

I have an application that takes input, either from the terminal directly or I can use a pipe to pass the output of another program into the stdin of this one. What I am trying to do is use python to generate the output so it's formatted correctly and pass that to the stdin of this program all from the same script. Here is the code:
#!/usr/bin/python
import os
import subprocess
import plistlib
import sys
def appScan():
os.system("system_profiler -xml SPApplicationsDataType > apps.xml")
appList = plistlib.readPlist("apps.xml")
sys.stdout.write( "Mac_App_List\n"
"Delimiters=\"^\"\n"
"string50 string50\n"
"Name^Version\n")
appDict = appList[0]['_items']
for x in appDict:
if 'version' in x:
print x['_name'] + "^" + x['version'] + "^"
else:
print x['_name'] + "^" + "no version found" + "^"
proc = subprocess.Popen(["/opt/altiris/notification/inventory/lib/helpers/aex- sendcustominv","-t","-"], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
proc.communicate(input=appScan())
For some reason this subprocess I am calling doesn't like what is coming into stdin. However if I remove the subprocess items and just have the script print to stdout and then call the script from the terminal (python appScan.py | aex-sendcustominv), aex-sendcustominv is able to accept the input just fine. Is there any way to take a functions output in python and send it to the stdin of an subprocess?
The problem is that appScan() only prints to stdout; appScan() returns None, so proc.communicate(input=appScan()) is equivalent to proc.communicate(input=None). You need appScan to return a string.
Try this (not tested):
def appScan():
os.system("system_profiler -xml SPApplicationsDataType > apps.xml")
appList = plistlib.readPlist("apps.xml")
output_str = 'Delimiters="^"\nstring50 string50\nName^Version\n'
appDict = appList[0]['_items']
for x in appDict:
if 'version' in x:
output_str = output_str + x['_name'] + "^" + x['version'] + "^"
else:
output_str = output_str + x['_name'] + "^" + "no version found" + "^"
return output_str
proc = subprocess.Popen(["/opt/altiris/notification/inventory/lib/helpers/aex- sendcustominv","-t","-"], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
proc.communicate(input=appScan())

Categories

Resources