New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add shlex.quote #53932
Comments
The only way to safely build shell command lines from inside of Python — which is necessary when sending commands across SSH, since that behaves like os.system() rather than like subprocess.call() — is to use the wonderful pipes.call() method to turn possibly-dangerous arguments, like filenames that might have spaces, special characters, and embedded "rm -r" calls, into perfectly quoted strings for an "sh"-like shell (say, bash or zsh). This call is already recommended on mailing lists, blog posts, and Stack Overflow — and since it doesn't start with a "_", I think its public use is fair game. But the "pipes" documentation itself doesn't officially mention or support it. I think it should be added to the Standard Library documentation for "pipes". So. Yeah. |
I think you mean pipe.quote in your message, not pipe.call. The subject looks correct. I'm not sure pipes is the best place for this, but I agree it should probably be documented in older versions. It seems to me we've had this discussion before about quoting command lines, how it applies differently between Windows and various shells, and which functions to expose. But having said that, I can't find a previous issue that discusses it. Not the least of my concerns is that pipes says it's available on Unix systems, despite the fact that I have it on a Windows machine. And I might need the functionality of passing a bash command from a Windows machine to a Unix machine, so we definitely need this cross platform. |
Eric referred to this thread: http://mail.python.org/pipermail/stdlib-sig/2010-May/thread.html |
I agree, I discovered this function (pipes.quote) only through recommendation here: http://stackoverflow.com/questions/4748344/whats-the-reverse-of-shlex-split I suggest that it be added to shlex, perhaps as shlex.quote. While the quoting style it performs, and the module it's found in are specific to Unix tools, the shlex module is available on non-Unix platforms. To this end, adding the function to shlex would make it available elsewhere, as well as be appropriately shell-related. |
Why do you want to move quote from pipes to shlex? The function is available, the issue here is lack of documentation. |
Two reasons: The pipes module is Unix only, but pipes.quote is useful on all platforms. Secondly pipes.quote pertains to shell command-lines, this is also the domain of shlex which already cross platform. In pipes, an import shlex.quote would more than sufficient. If this belongs in another separate bug I shall submit one. Please advise. |
Even if quote does not start with an underscore, its absence from the docs and from the module’s __all__ make it a private function. I propose to make it public as shlex.quote in 3.3 and deprecate pipes.quote for people that relied on it (i.e. move code from pipes/test_pipes to shlex/test_shlex, add doc, write a pipes.quote function that sends a DeprecationWarning and calls shlex.quote). |
Rather than doing a code deprecation you can just do 'from shlex import quote' in pipes (with a comment about backward compatibility). I don't think there is any real harm in leaving that kind of backward compatibility in place indefinitely. |
We would have had to do that anyway, since pipes needs to use the function. Agreed that a deprecation is not necessary. |
Yes, I know you have to do it anyway, that's why I used the adverb 'just' (as in 'just that, and nothing more') (I note that 'just' as an adverb tends to get overused by English speakers, and so loses some of its semantic value... :) |
Putting quote() into shlex sounds good to me. |
A note from Ian Bicking in http://mail.python.org/pipermail/stdlib-sig/2010-May/000948.html:
|
Someone on Stack Overflow suggested subprocess.list2cmdline. It’s one of those functions undocumented and absent from __all__ that somehow get found and used by some people. So when we make the patch, let’s include links to the new function doc from subprocess and pipes, and reply to the Stack Overflow thread. |
See also bpo-11827 about subprocess.list2cmdline. |
Here’s the patch, please review. |
New changeset 5966eeb0457d by Éric Araujo in branch 'default': |
New changeset 43c41e19527a by Éric Araujo in branch 'default': |
I suck at regexes, but the one I came up with lets quote pass the tests that existed for pipes.quote, so I figure it’s good. I did not change the string operations at the end of the function (+ and replace) as it was simple and working. In the absence of review or opposition here, I have committed my patch. Feedback welcome. |
Sorry I didn't look at the patch earlier. I thought we were just *moving* pipes.quote. Why is a new regex involved? |
Because I choose to follow Ian’s remark in msg127957:
I have not touched the tests, so I felt confident with my regex. FWIW, I’ve also changed the argument name, since the function is not limited to file names (as I hopefully made clear in the doc). |
Well, it's a micro-optimization (it would be interesting to benchmark, but not worth it). I find the original code much more readable than the regex, but it doesn't matter all that much. (And as far as optimization goes, using translate might be even faster.) |
str.translate is not an option, as the code does not replace but add characters (quotes). Out of sheer curiosity, I may actually benchmark this. |
You aren't using a regex to replace the quotes, either. >>> len('abcd'.translate(str.maketrans('', '', string.ascii_letters ))) > 0
False I don't know if this is faster than the corresponding search regex, but depending on how much overhead regex has, it might be. Note that the translate table can be pre-built, just like the compiled regex. |
+_find_unsafe = re.compile(r'[^\\w\\d@%_\\-\\+=:,\\./]').search \w already includes both \d and _, so (unless you really want to be explicit about it) they are redundant. Also keep in mind that they match non-ASCII letters/numbers on Python 3. r'[^\\w\\d@%_\\-\\+=:,\\./]' and r'[^\\w@%+=:,./-]' should therefore be equivalent. |
|
New changeset 8032ea4c3619 by Éric Araujo in branch '3.2': New changeset 6ae0345a7e29 by Éric Araujo in branch 'default': |
I have restored compatibility (see commit messages). |
-_find_unsafe = re.compile(r'[^\\w\\d@%_\\-\\+=:,\\./]').search FWIW there are still unnecessary escapes before '+' and '.', and possibly '-' ('-' doesn't need escaping only when it's at the end (or beginning) of the regex). |
Why can't pipes.quote can't be moved to shlex.quote verbatim as I originally proposed? Is there justification to also change it as part of the relocation? I think any changes to its behaviour should be a separate issue. |
This is IMO cosmetic and not as “important” as the duplicate characters already implied by the character class. Feel free to change it.
I took the opportunity of changing some convoluted code. |
New changeset 5d4438001069 by Ezio Melotti in branch 'default': |
See bpo-14616 for a doc edition related to this. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: