Prevent expansion of wildcards in non-quoted python script argument when running in UNIX environment

倖福魔咒の 提交于 2020-06-08 13:39:49

问题


I have a python script that I'd like to supply with an argument (usually) containing wildcards, referring to a series of files that I'd like to do stuff with. Example here:

#!/usr/bin/env python

import argparse
import glob 

parser = argparse.ArgumentParser()
parser.add_argument('-i', action="store", dest="i")
results = parser.parse_args()
print 'argument i is: ', results.i
list_of_matched_files = glob.glob(results.i)

In this case, everything works great if the user adds quotes to the passed argument like so:

./test_script.py -i "foo*.txt"

...but often times the users forget to add quotes to the argument and are stumped when the list only contains the first match because UNIX already expanded the list and argparse only then gets the first list element.

Is there a way (within the script) to prevent UNIX from expanding the list before passing it to python? Or maybe even just to test if the argument doesn't contain quotes and then warn the user?


回答1:


Its not UNIX that is doing the expansion, it is the shell.

Bash has an option set -o noglob (or -f) which turns off globbing (filename expansion), but that is non-standard.

If you give an end-user access to the command-line then they really should know about quoting. For example, the commonly used find command has a -name parameter which can take glob constructs but they have to be quoted in a similar manner. Your program is no different to any other.

If users can't handle that then maybe you should give them a different interface. You could go to the extreme of writing a GUI or a web/HTML front-end, but that's probably over the top.

Or why not prompt for the filename pattern? You could, for example, use a -p option to indicate prompting, e.g:

import argparse
import glob

parser = argparse.ArgumentParser()
parser.add_argument('-i', action="store", dest="i")
parser.add_argument('-p', action="store_true", default=False)

results = parser.parse_args()

if results.p:
    pattern = raw_input("Enter filename pattern: ")
else:
    pattern = results.i

list_of_matched_files = glob.glob(pattern)
print list_of_matched_files

(I have assumed Python 2 because of your print statement)

Here the input is not read by the shell but by python, which will not expand glob constructs unless you ask it to.




回答2:


No. Wildcards are expanded by the shell (Bash, zsh, csh, fish, whatever) before the script even runs, and the script can't do anything about them. Testing whether the argument contains quotes also won't work, as the shell similarly strips the quotes from "foo*.txt" before passing the argument to the script, so all Python sees is foo*.txt.




回答3:


You can disable the expansion using set -f from the command line. (re-enable with set +f).

As jwodder correctly says though, this happens before the script is run, so the only way I can think of to do this is to wrap it with a shell script that disables expansion temporarily, runs the python script, and re-enables expansion. Preventing UNIX from expanding the list before passing it to python is not possible.




回答4:


Here is an example for the Bash shell that shows what @Tom Wyllie is talking about:

 alias sea='set -f; search_function' 
 search_function() { perl /home/scripts/search.pl $@ ; set +f; } 

This defines an alias called "sea" that:

  1. Turns off expansion ("set -f")
  2. Runs the search_function function which is a perl script
  3. Turns expansion back on ("set +f")

The problem with this is that if a user stops execution with ^C or some such then the expansion may not be turned back on leaving the user puzzling why "ls *" is not working. So I'm not necessarily advocating using this. :).



来源:https://stackoverflow.com/questions/44971986/prevent-expansion-of-wildcards-in-non-quoted-python-script-argument-when-running

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!