grep unable to locate string when executing from python - python

Edit: I use Ubuntu 20.04.2 LTS and python 3.8.5
I got a bigger project where there are unused translation keys. I wrote a shell script to do this job. I exported some of the code to 2 testing files to narrow down on the weird behaviour. I am able to reproduce the bug but I fail to understand why it happens.
if sudo grep -r --include=\*.{js,html,json} --exclude-dir={node_modules,locale} 404_custom_error ../myreactproject/
then
echo 'found'
else
echo 'not found'
fi
If I run it via the terminal, it gets found.
import os
import subprocess
os.system("./testing.sh")
subprocess.call(['sh', 'testing.sh'])
But when I execute it from a python file, it gets a 'not found'.
os.getcmd() -> /home/{name}/projects/translation-cleaner
echo $PWD -> /home/{name}/projects/translation-cleaner
Note: The python file and shell script are in the same directory. The other project is in /home/{name}/projects/myreactproject.
That specific key is being found in ../myreactproject/src/views/Pages/Page404/Page404Admin.js:

I have 2 solutions but I have not tested them before on my previous Windows 10 machine since I migrated now fully to linx:
The proper one:
subprocess.call(['bash', './testing.sh'])
The dirty one:
I had to remove all brackets from my shell script. so my grep command looks like this:
grep -qr --include=*.js --include=*.html --include=*.json --exclude-dir=node_modules --exclude-dir=locale 404_custom_error ../myreactproject/;

Related

Bash script executed within Python with os.systems returns 0 but does not execute/ write

I have a bash script that I can run flawlessly in my Rpi terminal in its folder:
./veye_mipi_i2c.sh -r -f mirrormode -b 10
it works like this: Usage: ./veye_mipi_i2c.sh [-r/w] [-f] function name -p1 param1 -p2 param2 -b bus
options:
-r read
-w write
-f [function name] function name
-p1 [param1] param1 of each function
-p2 [param1] param2 of each function
-b [i2c bus num] i2c bus number
When I try to run it in Python (2) via my Spyder editor with os.system, I get a "0" return which I interpret as "succesfully executed" but in fact the script has not been executed and the functions have not been performed. I know this because the script is suppose to change the camera functioning and by checking the images I take afterwards, I can see that nothing has changed.
import os
status = os.system('/home/pi/VeyeMipi/Camera_Folder/veye_mipi_i2c.sh -w -f mirrormode -p1 0x04 -b 10')
print status
Any idea, what causes this? The bash script uses two other scripts that lie in the same folder location (read and write). Could it be, that it cannot execute these additional scripts when startet through Python? It does not make sense to me, but so do a lot of things....
Many thanks
Ok, I understand that my question was not exemplary because of the lack of a minimal reproducible example, but as I did not understand what the problem was, I was not able to create one.
I have found out, what the problem was. The script I am calling in bash requires two more scripts that are in the same folder. Namely the "write" script and "read" script. When executing in terminal in the folder, no problem, because the folder was the working directory.
I tried to execute the script within Spyder editor and added the file location to the PATH in the user interface. But still it would not be able to execute the "write" script in the folder.
Simply executing it in the terminal did the trick.
It would help if you fix your scripts so they don't depend on the current working directory (that's a very bad practice).
In the meantime, running
import subprocess
p = subprocess.run(['./veye_mipi_i2c.sh', '-r', '-f', 'mirrormode', '-b', '10'], cwd='/home/pi/VeyeMipi/Camera_Folder')
print(p.returncode)
which changes the directory would help.
Use subprocess and capture the output:
import subprocess
output = subprocess.run(stuff, capture_output=True)
Check output.stderr and output.stdout

Windows "No such file or directory"

I am trying to run a bash script from my Python code. I am calling the script in a subprocess like so:
preprocessed = subprocess.check_output([
'bash',
'../Paraphrase_Demo/models/processing_utils/preprocess_data_givenBPE.sh',
phrase, src_lang, tgt_lang, this_dir
])
Here is the script preprocess_data_givenBPE.sh:
#!/usr/bin/env bash
REMOTE_PATH=$4/processing_utils
SCRIPTS=$REMOTE_PATH/tiny-moses
TOKENIZER=$SCRIPTS/tokenizer.perl
DETOKENIZER=$SCRIPTS/detokenizer_v2.perl
CLEAN=$SCRIPTS/clean-corpus-n.perl
NORM_PUNC=$SCRIPTS/normalize-punctuation.perl
REM_NON_PRINT_CHAR=$SCRIPTS/remove-non-printing-char.perl
BPEROOT=$4/zhen/tools/subword-nmt/subword_nmt
text=$1
flan=$2
BPE=$4/$2$3/data/bpecodes
echo $text | perl $NORM_PUNC -l $flan | perl $REM_NON_PRINT_CHAR |
perl $TOKENIZER -a -l $flan -q | python3 $BPEROOT/apply_bpe.py -c $BPE | cat
When I run my Python program I get the following output:
Can't open perl script "C:/Users/Administrator/source/repos/Paraphrasing/Paraphrase_Demo/models/processing_utils/tiny-moses/normalize-punctuation.perl": No such file or directory
Can't open perl script "C:/Users/Administrator/source/repos/Paraphrasing/Paraphrase_Demo/models/processing_utils/tiny-moses/remove-non-printing-char.perl": No such file or directory
Can't open perl script "C:/Users/Administrator/source/repos/Paraphrasing/Paraphrase_Demo/models/processing_utils/tiny-moses/tokenizer.perl": No such file or directory
python3: can't open file 'C:/Users/Administrator/source/repos/Paraphrasing/Paraphrase_Demo/models/zhen/tools/subword-nmt/subword_nmt/apply_bpe.py': [Errno 2] No such file or directory
I have copy and pasted each of those paths into powershell and ls'd to verify that they are correct, but it still says it can't find them. What is going on here? This also happens if I run the bash script directly.
Edit: I've tried using backslashes in the path and received the same error. I also found this post: Bash: cannot execute a perl script using an absolute path?, so I tried using a relative path from the directory of my Bash script but it still says "No such file or directory."
After lots of debugging, I found the issue. While the paths I listed exist if I ls them in powershell, typing bash in powershell doesn't just open a bash shell, it actually changes the directory structure. I think this may be related to the Windows Subsystem for Linux, but the result is that C: changes to /mnt/c once inside the bash shell. Replacing this in all my paths, I was able to run my scripts.

Run a script using full path

I have a folder called TEST with inside :
script.py
script.sh
The bash file is :
#!/bin/bash
# Run the python script
python script.py
If I run the bash file like this :
./TEST/script.sh
I have the following error :
python: can't open file 'script.py': [Errno 2] No such file or directory
How could I do, to tell my script.sh to look in the directory (which may change) and to allow me to run it for inside the TEST directory ?
Tricky, my python file run a sqlite database and I have the same problem when calling the script from outside the folder, it didn't look inside the folder to find the database!
Alternative
You are able to run the script directly by adding this line to the top of your python file:
#!/usr/bin/env python
and then making the file executable:
$ chmod +x script.py
With this, you can run the script directly with ./TEST/script.py
What you asked for specifically
This works to get the path of the script, and then pass that to python.
#!/bin/sh
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
python "$SCRIPTPATH/script.py"
Also potentially useful:
You mentioned having this problem with accessing a sqlite DB in the same folder, if you are running this from a script to solve this problem, it will not work. I imagine this question may be of use to you for that problem: How do I get the path of a the Python script I am running in?
You could use $0 which is the name of the currently executing program, as invoked, combined with dirname which provides the directory component of a file path, to determine the path (absolute or relative) that the shell script was invoked under. Then, you can apply it to the python invocation.
This example worked for me:
$ t/t.sh
Hello, world!
$ cat t/t.sh
#!/bin/bash
python "$(dirname $0)/t.py"
Take it a step farther and change your current working directory which will also be inherited by python, thus helping it to find its database:
$ t/t.sh; cat t/t.sh ; cat t/t.py ; cat t/message.txt
hello, world!
#!/bin/bash
cd "$(dirname $0)"
python t.py
with(open('message.txt')) as msgf:
print(msgf.read())
hello, world!
From the shell script, you can always find your current directory: Getting the source directory of a Bash script from within. While the accepted answer to this question provide a very comprehensive and robust solution, your relatively simple case only really needs something like
#!/bin/bash
dir="$(dirname "${BASH_SOURCE[0]}")"
# Run the python script
python "$(dir)"/script.py
Another way to do it would be to change the directory from which you run the script:
#!/bin/bash
dir="$(dirname "${BASH_SOURCE[0]}")"
# Run the python script
(cd "$dir"; python script.py)
The parentheses ((...)) around cd and python create a subprocess, so that the directory does not change for the rest of your bash script. This may not be necessary if you don't do anything else in the bash portion, but is still useful to have if you ever decide to say source your script instead of running it as a subprocess.
If you do not change the directory in bash, you can do it in Python using a combination of sys.argv\[0\], os.path.dirname and os.chdir:
import sys
import os
...
os.chdir(os.path.dirname(sys.argv[0]))

Error in check_call() subprocess, executing 'mv' unix command: "Syntax error: '(' unexpected"

I'm making a python script for Travis CI.
.travis.yml
...
script:
- support/travis-build.py
...
The python file travis-build.py is something like this:
#!/usr/bin/env python
from subprocess import check_call
...
check_call(r"mv !(my_project|cmake-3.0.2-Darwin64-universal) ./my_project/final_folder", shell=True)
...
When Travis building achieves that line, I'm getting an error:
/bin/sh: 1: Syntax error: "(" unexpected
I just tried a lot of different forms to write it, but I get the same result. Any idea?
Thanks in advance!
Edit
My current directory layout:
- my_project/final_folder/
- cmake-3.0.2-Darwin64-universal/
- fileA
- fileB
- fileC
I'm trying with this command to move all the current files fileA, fileB and fileC, excluding my_project and cmake-3.0.2-Darwin64-universal folders into ./my_project/final_folder. If I execute this command on Linux shell, I get my aim but not through check_call() command.
Note: I can't move the files one by one, because there are many others
I don't know which shell Travis are using by default because I don't specify it, I only know that if I write the command in my .travis.yml:
.travis.yml
...
script:
# Here is the previous Travis code
- mv !(my_project|cmake-3.0.2-Darwin64-universal) ./my_project/final_folder
...
It works. But If I use the script, it fails.
I found this command from the following issue:
How to use 'mv' command to move files except those in a specific directory?
You're using the bash feature extglob, to try to exclude the files that you're specifying. You'll need to enable it in order to have it exclude the two entries you're specifying.
The python subprocess module explicitly uses /bin/sh when you use shell=True, which doesn't enable the use of bash features like this by default (it's a compliance thing to make it more like original sh).
If you want to get bash to interpret the command; you have to pass it to bash explicitly, for example using:
subprocess.check_call(["bash", "-O", "extglob", "-c", "mv !(my_project|cmake-3.0.2-Darwin64-universal) ./my_project/final_folder"])
I would not choose to do the job in this manner, though.
Let me try again: in which shell do you expect your syntax !(...) to work? Is it bash? Is it ksh? I have never used it, and a quick search for a corresponding bash feature led nowhere. I suspect your syntax is just wrong, which is what the error message is telling you. In that case, your problem is entirely independent form python and the subprocess module.
If a special shell you have on your system supports this syntax, you need to make sure that Python is using the same shell when invoking your command. It tells you which shell it has been using: /bin/sh. This is usually just a link to the real shell executable. Does it point to the same shell you have tested your command in?
Edit: the SO solution you referenced contains the solution in the comments:
Tip: Note however that using this pattern relies on extglob. You can
enable it using shopt -s extglob (If you want extended globs to be
turned on by default you can add shopt -s extglob to .bashrc)
Just to demonstrate that different shells might deal with your syntax in different ways, first using bash:
$ !(uname)
-bash: !: event not found
And then, using /bin/dash:
$ !(uname)
Linux
The argument to a subprocess.something method must be a list of command line arguments. Use e.g. shlex.split() to make the string be split into correct command line arguments:
import shlex, subprocess
subprocess.check_call( shlex.split("mv !(...)") )
EDIT:
So, the goal is to move files/directories, with the exemption of some file(s)/directory(ies). By playing around with bash, I could get it to work like this:
mv `ls | grep -v -e '\(exclusion1\|exclusion2\)'` my_project
So in your situation that would be:
mv `ls | grep -v -e '\(myproject\|cmake-3.0.2-Darwin64-universal\)'` my_project
This could go into the subprocess.check_call(..., shell=True) and it should do what you expect it to do.

Execute bash script from URL using python

Assume I have a file at http://mysite.com/myscript.sh that contains:
#!/bin/bash
echo "Hello $1"
From the command line, I can execute my script (without downloading it) using the following command:
bash <(curl -s http://mysite.com/myscript.sh) World
Now, instead of executing the above command from the command line, I want to execute it from a python script. I tried doing the following:
import os
os.system('bash <(curl -s http://mysite.com/myscript.sh) World')
...but I get the following error:
sh: -c: line 0: syntax error near unexpected token `('
How do I make this execute correctly in python?
Evidently, os.system runs its command through /bin/sh, which usually causes whichever shell it's linked to to drop to a compatibility mode that doesn't include the <(...) construction. You can get around it by either storing the result in a temporary file or using another level of shell. Ugly, but it works.
os.system('bash -c "bash <(curl -s http://mysite.com/myscript.sh) World"')
There is a libcurl for python so you don't have to go the way around to command line behaviour. Here's the function list that should really do it - have never run remote scripts myself though. If you need installing the python binding, the instructions are here.
import curl

Categories