Make CLI command compatible as pipe - python

I am using Click to create CLI tool.
I want to create a command that can be pipeable.
For example,
echo 'Hello world' | customcmd > hello.txt
where customcmd is a command which takes a stdin input and returns stdout.

Put a shebang at 1st line of the customcmd file:
#! /usr/bin/env python
and set the executable bit:
$ chmod a+x customcmd
Then you'll be good to go, e.g. $ echo Hello | ./customcmd
cf exec

Related

Python script runs on command line but not from .sh file

I'm attempting to create a .sh file to batch a number of runs of a neural network on Python whilst on holidays.
At the moment I have been calling this from the command line:
python neural_network_trainer.py [args]
I now have a .sh script written:
#!/bin/bash
python neural_network_trainer.py [args]
# Repeated with varied args
That I am attempting to call in the same terminal as the original command line was running:
./august_hols.sh
I get the following error:
File "/data/Python-3.6.9/lib/python3.6/site.py", line 177
file=sys.stderr)
^
SyntaxError: invalid syntax
Where the Python install is in /data (for reasons).
Running which on the command line reports the correct Python directory set via an alias in ~/.bashrc:
alias python=/data/Python-3.6.9/bin/python3
But running which between the Bash shebang and the first python call reports /bin/python.
I've attempted to set the alias again at the start of the .sh script to no avail. I'm scratching my head as this is exact process I have used elsewhere, albeit not on this precise PC. I can copy the exact command from the top of the bash file into the terminal and it runs fine, try and call ./august_hols.sh and get the above Python error.
Where is Bash getting that path from, and why is it not using my expected route through ~/.bashrc?
Bash sub-shell does not inherit alias in the main shell
You can source the script (run in the main shell), instead of execute it (run in the sub-shell)
source script.sh
EDIT:
Solution 2:
Run bash as the login shell so ~/.bashrc is executed, so your alias is loaded before your script.
The subshell needs to be interactive to enable alias, because alias is enabled by default only for interactive shell, but script is non-interactive by default.
bash --login -i script.sh
Solution 3:
Similar to above, except alias is enabled explicitly
bash --login -O expand_aliases script.sh
Have you tried:
python=/data/Python-3.6.9/bin/python3 ./[your_bash].sh
In your .sh
Do this
#!/usr/bin/env bash
export PATH=/data/Python-3.6.9/bin:$PATH
exec python neural_network_trainer.py "$#"
Aliases are tricky.
A maybe more nasty solution
mapfile < <(declare -p | grep -m 1 BASH_ALIASES) && bash script.sh "${MAPFILE[#]}"
within your script you will need
shopt -s expand_aliases
eval $1
echo ${BASH_ALIASES[python]}
python --version
How about this:
#!/bin/bash
/data/Python-3.6.9/bin/python3 neural_network_trainer.py [args]
# Repeated with varied args

Python script with executable permission says "Command Not Found"

I have a python script abc.py. Inside a shell script file, I call it ./abc.py
Inside abc.py, at the top, I have #!/usr/bin/python
test -x abc.py && echo true || echo false return true
On executing the shell script, it says ./abc.py: Command not found.
It works if I call it as python ./abc.py instead of just ./abc.py
The issue is only with this abc.py file that I created today. The older python scripts in the same directory with different purpose and names work without any issue.
I have referred the correct path of the file BTW. What could be the issue?
In tcsh, this happens when the interpreter is invalid:
$ cat foo
#!/invalid
$ tcsh -c './foo'
./foo: Command not found.
$ bash -c './foo'
bash: ./foo: /invalid: bad interpreter: No such file or directory
This could be for several reasons. Perhaps your path is wrong for your system:
% type python
python is /usr/local/bin/python
in this case the script needs to start with #!/usr/local/bin/python instead.
Alternatively, the script could have Windows line endings (carriage returns):
$ cat -v foo
#!/usr/bin/python^M
...^M
In this case, save it with Unix line endings instead.
Trying to replicate your setup as follows:
File: asdf.py
#!/usr/bin/python
print("Hello World")
File: asdf.sh
#!/bin/bash
if [ -x asdf.py ]; then ./asdf.py ; else echo "Arrrrgh. File does not exist or does not have executable permisions"; fi
Now I save the files in the same directory, e.g. the Desktop, make them executable and run the shell script from the terminal.
usr#cmptr $ chmod +x asdf.{py,sh}
usr#cmptr $ ls -la asdf.{py,sh}
-rwxr-xr-x 1 usr usr 613 Mar 15 22:22 asdf.py
-rwxr-xr-x 1 usr usr 56 Mar 15 22:14 asdf.sh
usr#cmptr $ ./asdf.sh
Hello World
Now, maybe I have misunderstood your setup but this should work just fine.

Preserve return code from python script in Jenkins when used in a bash pipe

Consider this:
$ cat test.py
import sys
print "Doing something ..."
sys.exit(1)
$ python test.py
Doing something ...
$ echo $?
1
$ python test.py | tee log # used in Jenkins, but I need to capture rc of 1 as well
Doing something ...
$ echo $?
0
As you can see I am unable to capture the return code of 1 from the python script if I pipe the output to tee. Is there a way I can accomplish this ? This code is in Build->execute shell section in Jenkins.
Since I am unable to capture the rc of 1 the commands following the line continue to get executed, which I don't want to happen.
In bash you can use the PIPESTATUS array to get the exit status of each command in a pipeline:
python test.py | tee log
echo ${PIPESTATUS[0]}
Regarding "Since I am unable to capture the rc of 1 the commands following the line continue to get executed", you can add set -o errexit and set -o pipefail to the start of your script, it will then terminate directly if you get an error (even inside a piped command). Here a good resource with a more in-depth explanation.

Insert parameters to python program from shell script

I need to execute my python program from shell script so that the print commands in my python program will be exposed for reading from another program.
the shell script:
#!/bin/bash
if [ $# -lt 1 ] || [ $# -gt 2 ];then
echo "Usage: $0 APK <duration in seconds>"
exit 1;
fi
printf "$(python '/root/Desktop/DroidBox_4.1.1/scripts/droidbox.py' $1 $2 -c 'import sys; exec sys.stdin.read()')"
My python program should get the parametrs $1 and $2 but it doesn't recognize those as parametrs but taking -c and the command after it as the parametrs.
For answers like: getting the process input stream in my other project won't work for me. the only way that seems to be working is to use -c option and the command 'exec sys.stdin.read()'.
thank you.
It should work pretty well just the way you've written it. In a stripped down version here's what I get:
the (bash) test.sh script:
#!/bin/bash
python /tmp/test.py $1 $2
the (python) test.py script:
import sys
print "in python"
print sys.argv
and finally a shell session:
smassey#hacklabs:/tmp $ ./test.sh hello world
in python
['/tmp/test.py', 'hello', 'world']
As you can see, the bash script calls the python script which prints values to stdout so they're just as exposed as anything else directed to stdout:
smassey#hacklabs:/tmp $ ./test.sh hello world | grep python | tr 'a-z' 'A-Z'
IN PYTHON
The argparse module is very helpful as well. This allow you to add custom flags to your program (makes it more convenient to works with from a user's perspective as well).

how to make a python file run without py extension

I had a small python script that takes input from the command line arguments and done some
operations using the inputs taken and display the result
Below is the working example code
some_file.py
import sys
arguments = sys.argv
first_name = sys.argv[1]
second_name = sys.argv[2]
print "Hello {0} {1} !!!!".format(first_name,second_name)
Now i am executing this as
python some_file.py Steve jobs
Result :
Hello Steve Jobs !!!!
Now what all i want is, i don't want to use python command before file name and extension of python file name, that is i want to run the file as a command tool as below
some_file Steve Jobs
so what to do in order to run the python file as above ?
Unix-like OS solution: the first line of the file should be #!/usr/bin/python (or wherever the python interpreter is) and chmod u+x the script. Run it with ./some_file parameters.
If you want to launch it with some_file parameters simply make a link to the script in a directory which is already included into your PATH: sudo ln -s some_file /usr/bin.
So, here's the full procedure:
blackbear#blackbear-laptop:~$ cat > hw
#!/usr/bin/python
print "Hello World!"
blackbear#blackbear-laptop:~$ chmod u+x hw
blackbear#blackbear-laptop:~$ sudo ln -s hw /usr/bin
blackbear#blackbear-laptop:~$ hw
Hello World!
blackbear#blackbear-laptop:~$
make a symbolic link
ln -s some_file.py some_file
now you can type your cmd like this:
some_file Steve Jobs
you can run the same program in python shell by using execfile('path').

Categories

Resources