Recently, I have found the article about editing shell script while it's running.
Edit shell script while it's running
I prepared that code to reproduce the phenomenon with additional python script calling. I found echo in bash was NOT affected by editing while python script was affected.
Could someone explain this phenomenon? I have expected that all std outputs should be "modified".
test.sh
#!/bin/bash
sleep 30
echo "not modified"
python my_python.py
echo "not modified"
my_python.py
print("not modified")
Output result
$ bash test.sh // while sleeping, I edited test.sh and my_python.py to "modified"
not modified
modified
not modified
The bash script is already loaded in memory and executing and the results will not be affected until the next run. The python script is not loaded yet and is loaded in memory after you modify it.
If you do the reverse and launch the bash script from an equivalent python script, you will get the same behavior in reverse.
EDIT 05/10/2020
As pointed out by Gordon Davisson;
"Different versions of bash do different things. Some read the file byte-by-byte as they execute it, some I think load it in 8KB blocks (not necessarily the whole file), some do even more complicated things (AIUI it can also depend on the OS they're running under). See my answer Overwrite executing bash script files. Net result: do not count on any particular behavior."
That said, the OP's OS behavior seem to indicate a complete load of the script which explain the current behavior, albeit does not guarantee it.
Related
Here is a minimal working example:
I have a python script test.py that contains:
print("Hello")
and I have a bash script test.sh that calls that python function
#!/usr/bin/bash
python test.py
and when I run test.sh from terminal there is no output.
Based on a few similar questions, I have tried appending sys.stdout.flush and calling python -u instead, but there is still no output.
How do I get the output of print to show up?
Edit
In more complicated examples, how do I ensure that python print statements appear when called within a bash script? And ensure that those statements can be appropriately redirected with, e.g. &> operators?
(Also, I tried searching for a while before asking, but couldn't find a question that addressed this exactly. Any links to more thorough explanations would be greatly appreciated!)
My python output was missing when assigning it to a bash variable. I can't replicate your exact issue either, but I think this could help:
#!/usr/bin/bash
script_return=$(python test.py)
echo "$script_return"
In the pip program, the She-bang is
#!/usr/local/bin/python
if __name__ == "__main__":
# Python program body
while in the Install Certificates.command that Python Launcher offers:
#!/bin/sh
/Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6 << "EOF"
# python program body
EOF
Are there any differences between those two approaches? And is there any reason to prefer one to another?
It seems to me they are all the same, except for the second one has one more bash subroutine. Is this right?
In the general case, you simply want to specify the interpreter you actually want.
Outside of this, you sometimes see workarounds like this as portability hacks. On POSIX systems, /usr/bin/env covers the majority of scenarios quite nicely; but if you need portability to older or otherwise peculiar systems, falling back to the lowest common denominator and then working your way back up to a place where you can reliably run e.g. Python on a variety of systems may require all kinds of unobvious constructs. (The previous - upvoted! - answer by Dan D. is a good example.)
There are also cases where you want sh to set something up (fetch some environment variables which are specified in a file which uses sh syntax, for example) and then hand over execution to Python;
#!/bin/sh
# source some variables
. /etc/defaults/myenv.sh
# Then run Python
exec env python -c '
# ... Your Python script here
' "$#"
There is a line length limit on the #! line. Perhaps they did that to get around that.
The options are the path to the program but only if it is short enough. Use of env python which uses the path. Or chain loading like this.
This specific code for the Install Certificates.command script was introduced in Python Issue #17128. As far as I can tell, the author hasn't explained why he wrote the code this way.
Note that .command files are Shell scripts on Mac OS X that can be executed by double-clicking on them in Finder.
I believe the likely explanation is that the author simply wanted to honour Mac OS X's expectation that .command files should be Shell scripts.
You could test this by placing the following content in a file ~/Desktop/test.command:
#!/usr/bin/env python
print "Hello world"
Then view the Desktop folder in Finder, and note that it is reported as a "shell" file:
(Although it is reported incorrectly as a Shell file, this Python script can still be executed by double-clicking on it. It doesn't break Finder or anything.)
To answer the specific question, one reason for preferring this pattern might be, as Dan D. said, to avoid a Shebang line limit.
In general, you would prefer to use #!/usr/bin/env python as your Shebang line. Creating a Bash Heredoc (i.e. the python3.6 << EOF pattern) would create all sorts of problems, such as your syntax highlighting won't work, you have to watch out for Bash variable interpolation inside the Heredoc, etc.
I apologize if this is a duplicate, I couldn't find any other examples of this question.
I'm trying to write a program for natural language recognition, and I was reading a blog post where someone had attempted to do something similar and it recommended using these two lines to capture the output.
#capture output of script
./get-language.py | tee preptxt
I can't figure out what this code is attempting to do. I assume it's running the get-language file, but that syntax doesn't look correct to me. Could someone point me in the right direction?
On Unix systems you can run executable files with /path/to/my/executable.
This is nothing python specific.
As . is the current working directory, you are executing the get-language.py script located in the current directory.
However, there are two things you need to do, to get this working for your scripts:
1. add a shebang
This is the first line of your script, it tells the shell which program to use.
To use the python interpreter that is first in the PATH use:
#!/usr/bin/env python
2. Add the permissions to make your script executable:
You need to permit execution of your script. This can be done with chmod:
chmod +x myscript.py
The last part is a so called piping operation.
If you call two programs like this:
$ program_a | program_b
The output (stdout) of program_a is fed into program_b.
That's a shell thing, not Python. . is the current directory; you're running get-language.py from there.
This is not a line of python, but rather a shell script.
It is running a script called get-language.py (which I assume was described elsewhere on that blog and does the actual language processing), and then it is "piping" that output through the unix command line program tee, which stores the output in a file.
Piping takes the output of one program, and uses it as the input of another program.
I'm trying to change the terminal directory through a python script. I've seen this post and others like it so I know about os.chdir, but it's not working the way I'd like. os.chdir appears to change the directory, but only for the python script. For instance I have this code.
#! /usr/bin/env python
import os
os.chdir("/home/chekid/work2/")
print os.getcwd()
Unfortunately after running I'm still in the directory of the python script (e.g. /home/chekid) rather than the directory I want to be in. See below.
gandalf(pts/42):~> pwd
/home/chekid
gandalf(pts/42):~> ./changedirectory.py
/home/chekid/work2
gandalf(pts/42):~> pwd
/home/chekid
Any thoughts on what I should do?
Edit: Looks like what I'm trying to do doesn't exist in 'normal' python. I did find a work around, although it doesn't look so elegant to me.
cd `./changedirectory.py`
You can't. The shell's current directory belongs to the shell, not to you.
(OK, you could ptrace(2) the shell and make it call chdir(2), but that's probably not a great design, won't work on Windows, and I would not begin to know how to do it in pure Python except that you'd probably have to mess around with ctypes or something similar.)
You could launch a subshell with your current working directory. That might be close enough to what you need:
os.chdir('/path/to/somewhere')
shell = os.environ.get('SHELL', '/bin/sh')
os.execl(shell, shell)
# execl() does not return; it replaces the Python process with a new shell process
The original shell will still be there, so make sure you don't leave it hanging around. If you initially call Python with the exec builtin (e.g. exec python /path/to/script.py), then the original shell will be replaced with the Python process and you won't have to worry about this. But if Python exits without launching the shell, you'll be left with no shell open at all.
You can if you cheat: Make a bash script that calls your python script. The python script returns the path you want to change directory to. Then the bash script does the acctual chdir. Of course you would have to run the bash script in your bash shell using "source".
The current working directory is an attribute of a process. It cannot be changed by another program, such as changing the current working directory in your shell by running a separate Python program. This is why cd is always a shell built-in command.
You can make your python print the directory you want to move to, and then call your script with cd "$(./python-script.py)". In condition your script actually does not print anything else.
To simplify, I have batch file which runs multiple python programs:
start "01" /wait "C:\python27\python.exe" test1.py
start "02" /wait "C:\python27\python.exe" test2.py
But I found that even if test1.py is not run because of its error, it simply moves on to run test2.py.
It even just closes the window for test1.py as soon as it confronts that error, and just creates another window for test2.py
Of course, if I run test1.py separately by running
python test1.py
then it prints all error messages.
Since I have tens of python files in one batch, it becomes very hard to know which one of these caused the error, and I can't even know what's that error because I can't see the error messages.
How can I make it stop (but not closes the window) when it meets some error, and shows me the error message?
I do not know much about Python. But according to the question it outputs messages to stdout and stderr which only console applications do.
But if python.exe is indeed a console application and not a Windows (GUI) application, it is not really necessary to use start "title" /wait as this just results in calling console application python.exe in a separate command line interpreter process which is the reason why there is no output of python.exe displayed in command line interpreter process in which is executed the batch file.
I suggest to simply try:
#echo off
echo Calling Python with script test1.py.
"C:\python27\python.exe" test1.py
if errorlevel 1 pause
echo Calling Python with script test2.py.
"C:\python27\python.exe" test2.py
if errorlevel 1 pause
For error handling, see for example:
Exit codes in Python
get the exit code for python program
Testing for a Specific Error Level in Batch Files
Correct Testing Precedence of Batch File ERRORLEVELs
Windows documentation for command If
Please use the search feature of Stack Overflow explained on help page How do I search? and also WWW search engines. You surely do nothing which was not already done by other Python users as well and therefore also asked already most likely very often.
We expect that questioners try to find the solution by themselves and not asking others for making their job, see help page What topics can I ask about here?