Having issues with a shell command in Python - python-3.x

I am currently studying Python. In my course I have got to reading files. My tutor is showing me the following syntax....
!cat data_file/sample.txt
When he executes this command on screen it lets him view the text contents of the file.
When I execute the code it gives me an error of cat not recognized as a valid shell command in Python.
I have read through as much Python documentation as I can and have come up with nothing!
Can anyone please help??

Its not a python specific functionality. Please use Jupyter (Ipython).

Your tutor is probably using jupyter, which in turn uses IPython.
The bang (!) means that Ipython will execute a system shell command, like:
!cat data_file/sample.txt
In this case output the contents of a txt file. This functionality is documented here

Related

How to execute a shell program taking inputs with python?

First of all, I'm using Ubuntu 20.04 and Python 3.8.
I would like to run a program that takes command line inputs. I managed to start the program from python with the os.system() command, but after starting the program it is impossible to send the inputs. The program in question is a product interface application that uses the CubeSat Space Protocol (CSP) as a language. However, the inputs used are encoded in a .c file with their corresponding .h header.
In the shell, it looks like this:
starting the program
In python, it looks like this:
import os
os.chdir('/home/augustin/workspaceGS/gs-sw-nanosoft-product-interface-application-2.5.1')
os.system('./waf')
os.system('./build/csp-client -k/dev/ttyUSB1')
os.system('cmp ident') #cmp ident is typically the kind of command that does not work on python
The output is the same as in the shell but without the "cmp ident output", that is to say it's impossible for me to use the csp-client#
As you can probably see, I'm a real beginner trying to be as clear and precise as possible. I can of course try to give more information if needed. Thanks for your help !
It sounds like the pexpect module might be what you're looking for rather than using os.system it's designed for controlling other applications and interacting with them like a human is using them. The documentation for it is available here. But what you want will probably look something like this:
import pexpect
p = pexpect.spawnu("/home/augustin/workspaceGS/gs-sw-nanosoft-product-interface-application-2.5.1/build/csp-client -k/dev/ttyUSB1")
p.expect("csp-client")
p.sendline("cmp indent")
print(p.read())
p.close()
I'll try and give you some hints to get you started - though bear in mind I do not know any of your tools, i.e. waf or csp-client, but hopefully that will not matter.
I'll number my points so you can refer to the steps easily.
Point 1
If waf is a build system, I wouldn't keep running that every time you want to run your csp-client. Just use waf to rebuild when you have changed your code - that should save time.
Point 2
When you change directory to /home/augustin/workspaceGS/gs-sw-nanosoft-product-interface-application-2.5.1 and then run ./build/csp-client you are effectively running:
/home/augustin/workspaceGS/gs-sw-nanosoft-product-interface-application-2.5.1/build/csp-client -k/dev/ttyUSB1
But that is rather annoying, so I would make a symbolic link to that that from /usr/local/bin so that you can run it just with:
csp-client -k/dev/ttyUSB1
So, I would make that symlink with:
ln -s /home/augustin/workspaceGS/gs-sw-nanosoft-product-interface-application-2.5.1/build/csp-client /usr/local/bin/csp-client
You MAY need to put sudo at the start of that command. Once you have that, you should be able to just run:
csp-client -k/dev/ttyUSB1
Point 3
Your Python code doesn't work because every os.system() starts a completely new shell, unrelated to the previous line or shell. And the shell that it starts then exits before your next os.system() command.
As a result, the cmp ident command never goes to the csp-client. You really need to send the cmp ident command on the stdin or "standard input" of csp-client. You can do that in Python, it is described here, but it's not all that easy for a beginner.
Instead of that, if you just have aa few limited commands you need to send, such as "take a picture", I would make and test complete bash scripts in the Terminal, till I got them right and then just call those from Python. So, I would make a bash script in your HOME directory called, say csp-snap and put something like this in it:
#/bin/bash
# Extend PATH so we can find "/usr/local/bin/csp-client"
PATH=$PATH:/usr/local/bin
{
# Tell client to take picture
echo "nanoncam snap"
# Exit csp-client
echo exit
} | csp-client -k/dev/ttyUSB1
Now make that executable (only necessary once) with:
chmod +x $HOME/csp-snap
And then you can test it with:
$HOME/csp-snap
If that works, you can copy the script to /usr/local/bin with:
cp $HOME/csp-snap /usr/local/bin
You may need sudo at the start again.
Then you should be able to take photos from anywhere just with:
csp-snap
Then your Python code becomes easy:
os.system('/usr/local/bin/csp-snap')

Why does shell/bash commands show strange behaviour in Google Collaboratory?

I am using a set of bash shells and Python3 shells in my Google Collab notebook.
Usually, the bash scripts and shell commands are executed as
!wget "somelink"
but I noticed that at times the change directory instruction!cd /content/
usually seems to work but in most cases, but sometimes, it requires %cd /content/
I can't seem to know why does this happen. I can't provide a reproducible example but can say that this problem occurs after running shell scripts (file with .sh extension).
Another strange behavior is: When I run a bash script, usually it can be done as !script.sh but when I edit the script or tried to replace it, I get the
/bin/bash: script.sh: Permission denied
Though this answer helped me get it work by using
!bash script.sh
How can I understand this behaviour?

Can I run a script that uses 2 different command lines?

Sorry if the title is vague, I am fairly new to Linux and I don't really know how else to put it. I am creating a script and when I run it, I got it to run Sage but after it does so, the next command isn't executed. I presume this is because the first couple were in the standard Terminal (bash?) and everything after ./sage isn't -- here's the script:
#!/bin/bash
cd /home/alex/Desktop/sage-7.6
./sage
#I also tried wait ${!} here but it didn't work
notebook("/home/alex/Desktop/sage-7.6/projects/zero forcing.sagenb")
How might I enter the last command in Sage after it opens (assuming it's possible)? Thanks!
Edit: Here's a picture of my problem. Sage runs but I can't get it to execute the notebook() command after it opens.
You need to run notebook() as sage code using the -c option mentioned [ here ]. Try the below code.
#!/bin/bash
/home/alex/Desktop/sage-7.6/sage # You can run the interactive shell directly
# At this point you have completely exited the sage interactive shell
# Presumably you want to run the below 'notebook()' after every interactive shell
# In that case do
/home/alex/Desktop/sage-7.6/sage -c 'notebook("/home/alex/Desktop/sage-7.6/projects/zero forcing.sagenb")'
I think what you really want is just to have one command that launches a notebook with a given name.
It turns out that in many Linux/Unix applications, there is automatic help at the command line. Try
/home/alex/.../sage -n -h
to get some help on the notebook. In particular,
sage -n -h --notebook=sagenb
gives a very, very long list of options, the first of which shows that
sage --notebook=sagenb directory=tp
will give you a new sage notebook server in the directory tp.sagenb.
All this said, I should also point out that the sagenb (sadly) is slowly becoming a legacy project in favor of the Jupyter notebook. In Sage 8.0 a conversion from sagenb to Jupyter will become the default, and even now you can just do
sage --notebook=jupyter --notebook-dir=/home/foo/bar
for that to start up.

Python: which directory to work from

I'm on Windows 7 and using Python 3.6. The PATH has C:\Python36-32 and C:\Python36-32\scripts. This is my first foray into Python and I am working with a one line script which is merely:
print("hello")
and I'm already running into trouble.
I installed Python into C:\Python36-32. I saved hello.py to C:\Users\shea\Documents. If I open IDLE and try
>>> C:\Python36-32\python.exe C:\Users\shea\Documents\hello.py
SyntaxError: unexpected character after line continuation character
or
>>> python.exe hello.py
SyntaxError: invalid syntax
The first attempt came from a question or other reading somewhere else, I've been searching for over 2 hours for this question, that said that the complete path to the program needs to be given. Apparently, I need to add something else to another PATH to get to just using python ..., but I'm not worried about that at the moment. The 2nd attempt is just me trying something apparently easy out of frustration and that doesn't work either. I get the same problems with cmd. I don't know what is behind either problem. From the questions I've looked at, Python doesn't like more text after "\", but I don't know how I'd say what the name of the script is that I want to run with python.exe.
I think part of the problem is that the script is not in the same directory as python.exe, but I am not sure of that. Can I work with Python this way? If so, what is the right syntax to get Python to return the simple "hello" in IDLE or the cmd terminal?
The IDLE is not the same as a terminal shell.
You can do: File -> Open and open your file then Run it from Run menu or by pressing F5.
When you run IDLE you are running the python interpreter, not a regular shell. The python interpreter works on a specific directory, which you can check by doing:
>>> import os
>>> os.getcwd()
The directory it will output it's the directory the interpreter is currently in. You can change the directory the interpreter is currently in by doing:
>>> os.chdir(r'C:\Users')
In this case i changed the directory to 'C:\Users'. You can run os.getcwd() again to confirm the directory changed.
Withing the interpreter, you can run scripts using the import(<path_to_script>) call:
>>> import(r'myscript.py')
Since i only gave the name of the file, it will search for the file on the directory the interpreter is in. Since i put the interpreter in 'C:\Users', it'll look for a 'C:\Users\myscript.py' file and run the code in it. You can also pass the complete path to the import call, in which case it'll run the script no matter where the interpreter is currently in. The r before the string just tells python to take the string as it is and to not look for special characters. This is important because if you indicate your paths using \ then python would take the next letter after every \ as a special character, and would not read the path correctly (for instance, \n is a special character which indicates a new line).
If you import a script, and then do changes to it, to run it again, use the reload call:
>>> reload(r'myscript.py')
If you just want to run this on a regular terminal you just need to do:
python <script_file>
Provided the folder to the python binary is already in the environment variable PATH of Windows. In a regular shell, what you have to put on <script_file> follows the same rules as if it were on the python interpreter: if your command shell is already in directory of your script, then give just the name of the file, otherwise give the complete path, using "" and /.

I cant use certain linux commands in a bash script altough I can use them in console

I am trying to write a bash script that utilizes the command mkvirtualenv.
I can use it in the console without a problem but as soons I as try to use it in a bash script I get ./run: line 1: mkvirtualenv: command not found
I am not aware of anything that would create such a situation.
Does anyone know why the bash script behaves like that?
The reason emerged form the comments below the question: mkvirtualenv is a function.
If you want the function to exist in the script, you can export it from your shell by
export -f mkvirtualenv

Resources