-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Try to make argument with quotes for external command better #6420
Conversation
let's try this to see if it helps folks with quoting. |
…#6420) * fix arg quote for external * adjust comment
@WindSoilder do you know if these changes were reverted somewhere? I can't get this stuff working right anymore. https://gist.github.com/fdncred/c55a7a83f41bb6b3aa48381dd44ed4f8 |
oof, this test doesn't work any longer, in Windows:
|
This works for me in the latest main.
For something like this, because we pass list to fzf, I think we need to quote the whole --preview='gitxxx'], like this:
|
I was testing on windows. This works on Mac but not Windows.
neither of the |
I'm not sure if it's introduced by this pr, I'll install fzf and try on mac today. |
Hi @fdncred , there are two ways to work around this:
We need to If we only quote from The rule is commented here: nushell/crates/nu-command/src/system/run_external.rs Lines 77 to 86 in 8564c53
2. don't pass list to fzf:
Could you please check if it works for you? |
And,
Here is an issue mentioned about this #6465, I'm sorry my computer is broken, I can't verify if it was introduced by this pr. |
Both of your solutions work in Mac. I'll test in Windows in a little while. |
Both of those work on Windows too. I'd still like to fix this problem though. This does not work on windows
|
As a new nu user I was bitten by this. Very unexpected behavior. I was just trying to use ripgrep and this happened:
From my perspective as a newbie that looks like "escape sequences don't work". Maybe a better solution than trying to cleverly handle quotes could be to add a custom string delimiter option so users can pick a delimiter that won't conflict with whatever they need to put in a string. That or have add string delimiter option that's very unlikely to conflict with anything such as |
This PR is a complete rewrite of `run_external.rs`. The main goal of the rewrite is improving readability, but it also fixes some bugs related to argument handling and the PATH variable (fixes #6011). I'll discuss some technical details to make reviewing easier. ## Argument handling Quoting arguments for external commands is hard. Like, *really* hard. We've had more than a dozen issues and PRs dedicated to quoting arguments (see Appendix) but the current implementation is still buggy. Here's a demonstration of the buggy behavior: ```nu let foo = "'bar'" ^touch $foo # This creates a file named `bar`, but it should be `'bar'` ^touch ...[ "'bar'" ] # Same ``` I'll describe how this PR deals with argument handling. First, we'll introduce the concept of **bare strings**. Bare strings are **string literals** that are either **unquoted** or **quoted by backticks** [^1]. Strings within a list literal are NOT considered bare strings, even if they are unquoted or quoted by backticks. When a bare string is used as an argument to external process, we need to perform tilde-expansion, glob-expansion, and inner-quotes-removal, in that order. "Inner-quotes-removal" means transforming from `--option="value"` into `--option=value`. ## `.bat` files and CMD built-ins On Windows, `.bat` files and `.cmd` files are considered executable, but they need `CMD.exe` as the interpreter. The Rust standard library supports running `.bat` files directly and will spawn `CMD.exe` under the hood (see [documentation](https://doc.rust-lang.org/std/process/index.html#windows-argument-splitting)). However, other extensions are not supported [^2]. Nushell also supports a selected number of CMD built-ins. The problem with CMD is that it uses a different set of quoting rules. Correctly quoting for CMD requires using [Command::raw_arg()](https://doc.rust-lang.org/std/os/windows/process/trait.CommandExt.html#tymethod.raw_arg) and manually quoting CMD special characters, on top of quoting from the Nushell side. ~~I decided that this is too complex and chose to reject special characters in CMD built-ins instead [^3]. Hopefully this will not affact real-world use cases.~~ I've implemented escaping that works reasonably well. ## `which-support` feature The `which` crate is now a hard dependency of `nu-command`, making the `which-support` feature essentially useless. The `which` crate is already a hard dependency of `nu-cli`, and we should consider removing the `which-support` feature entirely. ## Appendix Here's a list of quoting-related issues and PRs in rough chronological order. * #4609 * #4631 * #4601 * #5846 * #5978 * #6014 * #6154 * #6161 * #6399 * #6420 * #6426 * #6465 * #6559 * #6560 [^1]: The idea that backtick-quoted strings act like bare strings was introduced by Kubouch and briefly mentioned in [the language reference](https://www.nushell.sh/lang-guide/chapters/strings_and_text.html#backtick-quotes). [^2]: The documentation also said "running .bat scripts in this way may be removed in the future and so should not be relied upon", which is another reason to move away from this. But again, quoting for CMD is hard. [^3]: If anyone wants to try, the best resource I found on the topic is [this](https://daviddeley.com/autohotkey/parameters/parameters.htm).
Description
Fixes: #6399
Detail
In general, if one external arg is quoted,
nu
won't remove inner extra quotes.Else, if one external arg is not quoted,
nu
will try to remove inner extra quotes, which is implemented in #5846Summarized:
^echo --aa="bbbb"
==>--aa=bbbb
^echo "--aa='bbbb'"
==>--aa='bbbb'
^echo '--aa="bbb"'
==>--aa="bbb"
For complex argument mentioned in #6399 (comment):
If we want to use
$dump_command
as an argument, we can't use bare$dump_command
, because it's intepreted as:PGPASSWORD='db_secret' pg_dump -Fc -h 'db.host' -p '$db.port' -U postgres -d 'db_name' > '/tmp/dump_name'
We need to surrand $dump_command with ", and using them with String interpolation.
Ok...have to admit it's a bit annoying
or just
^echo "PGPASSWORD='db_secret' pg_dump -Fc -h 'db.host' -p '$db.port' -U postgres -d 'db_name' > '/tmp/dump_name'"
Tests
Make sure you've done the following:
Make sure you've run and fixed any issues with these commands:
cargo fmt --all -- --check
to check standard code formatting (cargo fmt --all
applies these changes)cargo clippy --workspace --features=extra -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect
to check that you're using the standard code stylecargo test --workspace --features=extra
to check that all the tests pass