I don't know if this is a problem with python or with the shell (zsh on linux), I've an argument like this: "#xyz" that starts with a "#"
python the_script.py first_argument #second_argument third_arg
I tried to escape # with \ or \\, or use "" but the program doesn't start. If I leave the # from #second_arguments everything's ok.
Perhaps the "#" is a glob character in zsh, expanding to all symbolic links in the current directory. Try escaping it with "##"?
Try running the argument list with echo, i.e:
echo the_script.py first_argument #second_argument third_arg
That way, you can figure out if it was expanded or passed as-is to the script.
Related
I have to use:
x=input()
subprocess.Popen(f'PowerShell -Executionpolicy byPass {x}\n')
To open an executable, but it does not allow me to use a path from the input of an variable that contains backslash or spaces that are not written in the following way:
'\\' for backslashes.
'\u0020' for spaces.
For C:\Users\Administrator\Desktop\Folder Name\executable.exe
it should look like this:
'PowerShell -Executionpolicy byPass C:\\Users\\Administrator\\Desktop\\Folder\u0020Name\\executable.exe'
How could I replace all those spaces and backslashes on the variable for those unicode equivalents?
I need the user to be able just to copy and paste the executable's path.
I tried this, but didn't work:
x=input()
x=x.replace('\','\\')
x=x.replace(' ','\u0020')
I'm using Python 3.
Do not try to use escaping on the Python side: \, when provided as part of a variable value needs no escaping, and neither do spaces.
For PowerShell's sake, however, file paths that contain spaces require quoting; when using PowerShell's CLI, double-quoting ("...") is needed.
Additionally, you use the -File CLI parameter explicitly in order to execute a script file, because, by default, the -Command parameter is implied in Windows PowerShell, which interprets the following argument(s) as PowerShell source code, after stripping unescaped " from them, which causes script file paths with spaces to break.
Note: This applies to Windows PowerShell, but is no longer strictly necessary in PowerShell (Core) 7+, which now defaults to -File rather than -Command.
Therefore:
import subprocess
print('Enter the path of the .ps1 script to execute:')
x=input()
subprocess.Popen(f'PowerShell -Executionpolicy ByPass -File "{x}"').wait()
Note: To avoid unnecessary processing and to ensure a more predictable runtime environment, consider preceding -File with the -NoProfile switch, which suppresses loading of PowerShell's profile files
See also:
Guidance on when to use -File vs. -Command
A comprehensive overview of PowerShell's CLI, in both editions.
As roeland's answer demonstrates, you may alternatively pass the arguments that make up the PowerShell CLI command line individually to subprocess.Popen(), as elements of an array.
While Python then conveniently takes care of double-quoting the elements if necessary on the command line it synthesizes behind the scenes (on Windows), the same rules discussed above apply here too: the script-file path argument must be qualified with -File in order for script paths with spaces to be invoked correctly:
subprocess.Popen(['PowerShell', '-Executionpolicy', 'ByPass', '-File', x]).wait()
The easiest way to pass arguments to a subprocess is to pass in the program with arguments as a list:
subprocess.Popen(['PowerShell', '-Executionpolicy', 'byPass', x])
This assumes x will only contain one single extra argument. If it potentially contains multiple arguments you’ll need to make a decision on how to split it, and how to handle paths with spaces.
Could someone explain how this shebang works?
#!/usr/bin/perl -e$_=$ARGV[0];exec(s/\w+$/python3/r,$_)
I've seen it posted twice here but not coming from Perl it looks like magic to me.
I ask as I would like to adjust the directory to a python environment relative to the script.
i.e #!../env/bin/python3 to (I'm just guessing here) #!/usr/bin/perl -e$_=$ARGV[0];exec(s/\w+$/env/bin/python3/r,$_)
Edit: I am trying to execute a simple ''Hello world" program.
#!/usr/bin/perl -e'$_=$ARGV[0];exec(s{\w+$}{exploit-env/bin/python3}r,$_)'
###############################
def main():
print('Hello world')
###############################
if __name__ == '__main__':
main()
Shebang handling isn't consistent across all systems[1], but your system apparently apparently executes what the following shell command would execute (assuming the file containing the shebang is /path/to/script):
/usr/bin/perl -e'$_=$ARGV[0];exec(s/\w+$/python3/r,$_)' /path/to/script
(The path to the script might not be an absolute path —it might be relative to the current directory— but doesn't matter here.)
The script produces /path/to/python3 from /path/to/script (by replacing the trailing "word" characters, which include letters, digits and underscore, but not /), then evaluates
exec('/path/to/python3', '/path/to/script')
The replaces the program running in the current process with a Python interpreter, passing the path to the script as an argument.
If I read between the lines correctly, you want to to run /path/to/../env/bin/python3 instead of /path/to/python3. In order to achieve that, use either of the following:
#!/usr/bin/perl -e$_=$ARGV[0];exec(s/\w+$/..\/env\/bin\/python3/r,$_)
or
#!/usr/bin/perl -e$_=$ARGV[0];exec(s{\w+$}{../env/bin/python3}r,$_)
/ needs to be escaped by \ when / is used as the delimiter (first solution), but we can change the delimiter to produce a more readable result (second solution).
That shebang you presented causes the arguments to be absorbed. Replace the $_ with #ARGV to pass them on.
#!/usr/bin/perl -e$_=$ARGV[0];exec(s{\w+$}{../env/bin/python3}r,#ARGV)
At least historically, some systems treat the entire sequence that follows #! as the path (i.e. no arguments allows), and some have very strict limits as to the length of the path.
I am trying to integrate a Python script into a bash script. However when I use the input() function, I am getting an EOFError. How can I fix this problem?
#!/bin/bash
python3 <<END
print(input(">>> "))
END
You cannot source both the script and the user input through the program's standard input. (That's in effect what you're trying to do. << redirects the standard input.)
Ideally, you would provide the script as command line argument instead of stdin using -c SCRIPT instead of <<EOF heredoc EOF:
#!/bin/bash
python3 -c 'print(input(">>> "))'
Note that you may need to mind your quoting and escaping in case you have a more complicated Python script with nested quotes.
You can still let the script run over multiple lines, if you need to:
#!/bin/bash
python3 -c '
import os.path
path_name = input("enter a path name >>> ")
file_exists = os.path.exists(path_name)
print("file " + path_name + " " +
("exists" if file_exists else "does not exist"))
'
Note that you will get into trouble when you want to use single quotes in your Python script, as happens when you want to print doesn't instead of does not.
You can work around that using several approaches. The one I consider most flexible (apart from putting you into quoting hell) is surrounding the Python script with double quotes instead and properly escape all inner double quotes and other characters that the shell interprets:
#!/bin/bash
python3 -c "
print(\"It doesn't slice your bread.\")
print('But it can', 'unsliced'[2:7], 'your strings.')
print(\"It's only about \$0. Neat, right?\")
"
Note that I also escaped $, as the shell would otherwise interpret it inside the surrounding double quotes and the result may not be what you wanted.
I'm trying to make some functions in python so that I can connect to a linux terminal and do stuff (like in this case, create a file). The code I have, works partially. The only thing that doesn't work is if you want to do something after you have entered the code. Like for instance you create the file and then want to navigate somewhere else (cd /tmp) for instance. Instead of doing the next command, it will just add to the file created.
def create_file(self, name, contents, location):
try:
log.info("Creating a file...")
self.device.execute("mkdir -p {}".format(location))
self.cd_path(location)
self.device.sendline("cat > {}".format(name))
self.device.sendline("{}".format(contents))
self.device.sendline("EOF") # send the CTRL + D command to save and exit I tried here with ^D as well
except:
log.info("Failed to create the file!")
The contents of the file is:
cat test.txt
#!/bin/bash
echo "Fail Method Requested"
exit 1
EOF
ls -d /tmp/asdasd
The order of commands executed is:
execute.create_file(test.txt, the_message, the_location)
execute.check_path("/tmp/adsasd") #this function just checks with ls -d if the directory exists.
I have tried with sendline the following combinations:
^D, EOF, <<EOF
I don't really understand how I could make this happen. I just want to create a file with a specific message. (When researching on how to do this with VI I got the same problem, but there the command I needed was the one for ESC)
If anyone could help with some input that would be great!!
Edit: As Rob mentioned below, sending the character "\x04" actually works. For anyone else having this issue, you can also consult this chart for other combinations if needed:
http://donsnotes.com/tech/charsets/ascii.html
You probably need to send the EOF character, which is typically CONTROL-D, not the three characters E, O, and F.
self.device.sendline("\x04")
http://wiki.bash-hackers.org/syntax/redirection#here_documents
Here docs allow you to use any file input termination string you like to represent end of file ( such as the literal EOF you're attempting to use now). Quoting that string tells the shell not to interpret expansions inside the heredoc content, ensuring that said content is treated as literal.
Using pipes.quote() here ensures that filenames with literal quotes, $s, spaces, or other surprising characters won't break your script. (Of course, you'll need to import pipes; on Python 3, by contrast, this has moved to shlex.quote()).
self.device.sendline("cat > {} <<'EOF'".format(pipes.quote(name)))
Then you can write the EOF as is, having told bash to interpret it as the end of file input.
Quote of the script:
!/bin/sh
## repo default configuration
##
REPO_URL='https://android.googlesource.com/tools/repo'
REPO_REV='stable'
...
magic='--calling-python-from-/bin/sh--'
"""exec" python -E "$0" "$#" """#$magic"
if __name__ == '__main__':
import sys
if sys.argv[-1] == '#%s' % magic:
del sys.argv[-1]
del magic
..all python from here on..
How can they put bash and python in a single script and make it run?
This is how I understand it:
The script is first invoked as a shell script and then calls python on line 23, so if you invoked the sync command on repo it would do the following:
"""exec" python -E "$0" "$#" """#$magic"
which I believe turns into:
exec "python -E "repo" "sync" "#--calling-python-from-/bin/sh--"
This then calls the script repo as a python script. You will notice that all of the syntax is legal in bash and python down to the exec line. The triple quotes on line 23 are really sweet, they work in the shell script and then work as a doc string in python. How awesome is that!
In python """ begin and end a docstring which can span multiple lines. Very roughly, it's a very special kind of comment that the python help system can read. In bash, I believe that the double quote is matched to the next double quote the interpreter encounters. So the first two quotes, quote the null string and it disappears from the interpreter. In our example, the next quotes quote the exec keyword. The last set of triple quotes, """#$magic", first quote the null string and then quote the #$magic argument. Since double quotes allow the variable $magic to be expanded, it becomes, #--calling-python-from-/bin/sh-- and passed as an argument.
If you look at the script with a text editor with syntax highlighting as a shell script and then as a python script, it's even easier to see. This is an extremely clever, way of starting the shell script and then giving control to python. Hope this helps!