I am a beginner at Python. Below is the testing code for Python's command line args. If executing from command line with different parameter formats, I get different results, but it feels strange, can anyone help me understand why?
1, $test.py d:\ --> this seems ok for os.walk call
2, $test.py 'd:\' --> this will cause nothing output
BTW: I used Python 2.7.3
Test code:
import os
import sys
if __name__ == '__main__':
argMock = 'D:\\'
path = len(sys.argv) > 1 and sys.argv[1] or argMock
for root, dirs, files in os.walk(path):
for name in files:
print name
Maresh and Jakub's answers are incorrect.
The command line argument d:\ will become the string "d:\".
The command line argument 'd:\' will become the string "'d:\'".
Running the following with input 'D:\':
print sys.argv[1] # $test.py 'D:\\'
print argMock
yields:
'D:\\'
D:\
The issue is that putting quote marks around something that is already considered a string will just include the quote marks as part of the string.
The problem doesn't come from your program, it comes from the shell interpretation.
When you write 'd:\' your shell interprets the backslash as an escaping command for the next caracter. Therefore you must escape the backslash like this: 'd:\\'
Related
from importlib.resources import path
import os, shutil, pathlib, fnmatch
import argparse
import time
parser = argparse.ArgumentParser()
parser.add_argument('--src', type=str)
parser.add_argument('--dst', type=str)
parser.add_argument('--pattern', type=str)
args = parser.parse_args()
def move_dir(src: str, dst: str, pattern: str = '*'):
if not os.path.isdir(dst):
pathlib.Path(dst).mkdir(parents=True, exist_ok=True)
for f in fnmatch.filter(os.listdir(src), pattern):
shutil.move(os.path.join(src, f), os.path.join(dst, f))
move_dir(args.dst(), args.src(), args.pattern())
time.sleep(5)
move_dir(r"C:\Users\user\Downloads", r"C:\Users\user\Documents\pdf", r"*.pdf")
Creating a script to move files based on pattern in a specific directory. Initially ran into the raw string error when I hard coded and solved by making the output raw as suggested here : How to move a file in Python?
PROBLEM
As I tested with the hard code and had to put r before the string I wanted to test moving back from to the old directory and then recopying all over again. (Code was ran correctly once without the 2nd to last 2 lines)
I think I'm now failing to do that when calling the argument string as the error returned shows double backslashes '\'
C:\Users\user\Documents\GitHub\personalUtilities>python downloadOrganizer.py --src "C:\Users\user\Documents\pdf" --dst "C:\Users\user\Downloads" --pattern "*.pdf"
usage: downloadOrganizer.py [-h] [--src SRC] [--dst DST] [--pattern PATTERN]
downloadOrganizer.py: error: argument --src: invalid path value: 'C:\\Users\\user\\Documents\\pdf'
I see a few articles on making a class to check if the directory exists but that wouldn't solve my problem if I'm passing the wrong string type and any article about this in the subject seems to be answering a different question or solving something else.
So whats the proper way to pass the source and destination directory strings from argparse?
Tried changing the type to path for src and dst but didn't change anything. tried adding r to the arg in the cli before the quote string that just made the directory extra wrong!
I have tried to execute a simple python command from cmd like C:\Users> stat.py < swagger.yaml > output.html, which executes stat.py by taking swagger.yaml as input argument and generates output.html file and it worked fine in cmd. But now i want to execute my stat.py file through another python file demo.py by passing the values swagger.yaml and output.html as sys.argv[0] and sys.argv[1] inside demo.py.
my command from cmd C:\Users> demo.py swagger.yaml output.html and my demo.py file is as follows..
# my demo.py file ....
import os
import sys
os.system('stat.py < sys.argv[1] > sys.argv[2]')
error - the system can not find the file specified.
Why i am getting this error and please any help to resolve it ..
Inside a normal string, no variable interpretation is applied. So you literally asked to read from a file named sys.argv[1] (possibly sys.argv1 if the file exists, thanks to shell globbing), and write to a file named sys.argv[2].
If you want to use the values sys.argv in your script, you need to format them into the string, e.g. with f-strings (modern Python 3.6 or so only):
os.system(f'stat.py < {sys.argv[1]} > {sys.argv[2]}') # Note f at beginning of literal
or on older Python 2.7, with str.format:
os.system('stat.py < {} > {}'.format(sys.argv[1], sys.argv[2]))
Note that however you slice it, this is dangerous; os.system is launching this in a shell, and arguments that contain shell metacharacters will be interpreted as such. It can't do anything the user didn't already have permission to do, but small mistakes by the user could dramatically change the behavior of the program. If you want to do this properly/safely, use subprocess, open the files yourself, and pass them in explicitly as stdin/stdout:
with open(sys.argv[1], 'rb') as infile, open(sys.argv[2], 'wb') as outfile:
subprocess.run(['stat.py'], stdin=infile, stdout=outfile)
This ensures the files can be opened in the first place before launching the process, doesn't allow the shell to interpret anything, and avoids the (minor) expense of launching a shell at all. It's also going to give you more useful errors if opening the files fails.
My project structure:
/Users/user1/home/bashScrpts/shellScript.sh
/Users/user1/home/pyScrpts/pyScrpt.py
From the shell script I want to call a function of pyScrpt.py
Content of
pyScrpt.py
def test():
return sys.argv[1]
shellScript.sh
DATA="testXX"
cmd="import sys;sys.path.insert(0, '/Users/user1/home/pyScrpts/pyScrpt');import pyScrpt; print pyScrpt.test()"
xy=$(python -c \'${cmd}\' "${DATA}")
echo $xy
Error I am getting:
File "<string>", line 1
'import
SyntaxError: EOL while scanning string literal
I don't see whats going wrong here.
Can anyone help me on this??
You just need to replace \' in \'${cmd}\' with double quotes "${cmd}".
Also you should add import sys to your pyScrpt.py.
I have never done this before, but i would hazard a guess that it may be due to the wrong function structure, it should read:
def test()
return sys.argv[1]
the string that contains a file looks like this in the console:
>>> target_file
'src//data//annual_filings//ABB Ltd//ABB_ar_2015.pdf'
I got the target_file from a call to os.walk
The goal is to build a command to run in subprocess.call
Something like:
from subprocess import call
cmd_ = r'qpdf-7.0.0/bin/qpdf --password=%s --decrypt %s %s' %('', target_file, target_file)
call([cmd_])
I tried different variations, setting shell to either True or False.
Replacing the // with /,\ etc.
The issue seems to be with the space in the folder (I can not change the folder name).
The python code needs to run on Windows
you have to define cmd_ as a list of arguments not a list with a sole string in it, or subprocess interprets the string as the command (doesn't even try to split the args):
cmd_ = ['qpdf-7.0.0/bin/qpdf','--password=%s'%'','--decrypt',target_file, target_file]
call(cmd_)
and leave the quoting to subprocess
As a side note, no need to double the slashes. It works, but that's unnecessary.
I'm trying to make a python script that search words in files.
If I pass txt it will only look in files with .txt extension, but I want to pass * as argument to search in every files.
if sys.argv[4] == "*"
Don't work and if I try
print sys.argv[4]
It print the name of the script
find.py
But not the same way as
print sys.argv[0]
As it will return
./find.py
So, someone already had this problem and, of course, solved it ?
Your shell attaches meaning to * as well. You need to escape it when calling your script to prevent the shell from expanding it:
python find.py \*
sys.argv[0] is the exact name passed used to run the script. That can be a relative path (./find.py, ../bin/find.py) or an absolute path, depending on how it was invoked. Use os.path.abspath() to normalize it.