fzf
fzf copied to clipboard
[Issue] Expanding {n} automatically adds quotes and character escapes
- [x] I have read through the manual page (
man fzf
) - [x] I have the latest version of fzf
- [x] I have searched through the existing issues
Info
- OS
- [ ] Linux
- [ ] Mac OS X
- [x] Windows
- [ ] Etc.
- Shell
- [ ] bash
- [ ] zsh
- [ ] fish
- [x] PowerShell
Problem / Steps to reproduce
I'm using this command:
fzf --preview="bat --style=numbers --color=always {2}" --bind "ctrl-b:execute(notepad++ -n{1} {2})"
This is executed when applying Ctrl+B
on a result:
notepad++ -n"12" "C:\\Work\\Test Folder\\File.txt"
I see that {2}
is automatically expanded with the properly escaped path.
But {1}
is causing issues. I would need to expand it without adding any quote, also without making use of any further tool such as sed/awk.
How could this be achieved in FZF?
Is this a problem specific to Windows environment? Because -n"12"
isn't a problem on *nix shells.
i.e. There's no difference between ls -al | sort -nk"5"
and ls -al | sort -nk5
The fact is that I wish to open the FZF selected file with Notepad++. It accepts these arguments:
notepad++ -n<LINE_NUM> <FILE_PATH>
<LINE_NUM>
must not include quotes ("
), otherwise, it won't work. Thus, I need to output {n}
without quotes.
Obviously, on Windows, this is not an issue strictly related to Notepad++, but potentially to every command-line application accepting arguments.
Thus, this issue should be kept into great account, in my opinion.
@junegunn unfortunately on Windows this "issue" makes it impossible to execute any command for example through:
type "C:\Scripts\FZF\Main.bat" | fzf --delimiter="\t" --bind "enter:execute({2})"
Main.bat
content:
p ping test.it
e notepad++ "C:\Work\Test.txt"
When trying for example to run the e
command, this will be wrongly returned by the {2}
operator instead:
"notepad++ \"C:\\Work\\Test.txt\""
External quotes have been automatically added by FZF, and internal "
and \
characters have been escaped. This makes it impossible to execute that command on Windows, through the FZF execute
function.
All of this would be solved by not adding the external quotes and by not escaping the "
and \
characters when using the {}
operator. That functionality should be made optional. Or, another operator should be added which outputs the extracted string with no added quotes/escapes.
I'm not familiar with Windows environment. On *nix system, you would run an arbitrary command string with sh -c
.
echo 'ls -al' | fzf --bind 'enter:execute:sh -c {}; sleep 1'
Maybe you can do similarly on Windows with execute(cmd /c {2})
?
I'm not familiar with Windows environment. On *nix system, you would run an arbitrary command string with
sh -c
.echo 'ls -al' | fzf --bind 'enter:execute:sh -c {}; sleep 1'
Maybe you can do similarly on Windows with
execute(cmd /c {2})
?
Just tried but the problem, unfortunately, still occurs. The issue lies in the way the fields are automatically quoted/escaped.
Maybe a solution as follows could be implemented?
Original behaviour:
{n} - replace with field n adding quotes and escaping characters
Expanded behaviour:
[n] - replace with field n as it is
or
${n} - replace with field n as it is
or
{$n} - replace with field n as it is
The $
symbol is just an example, but my proposal could help with fixing this unwanted behaviour in Windows once for all.
What do you think about it @junegunn ?
fzf implements special quoting mechanism for Windows cmd.exe. You might want to check out https://github.com/junegunn/fzf/commit/c4185e81e86e339ae2c18e5d9b596b7992ec179b and see if there's room for improvement.
Have you tried execute(cmd /c {f2})
?
A placeholder expression with f flag is replaced to the path of a temporary file that holds the evaluated list.
fzf implements special quoting mechanism for Windows cmd.exe. You might want to check out c4185e8 and see if there's room for improvement.
How could I try/build it in Windows?
Have you tried
execute(cmd /c {f2})
?A placeholder expression with f flag is replaced to the path of a temporary file that holds the evaluated list.
Yes, but cmd
reports an error:
C:\Users\User\AppData\Local\Temp\fzf-preview-571750557
It seems as the temporary output file is missing .bat
or .cmd
extension, I suppose?
Hi, I am also interested in this. Not being able to suppress the double quotes around placeholders was first issue I noticed when starting with fzf on Windows.
I have got some observations so far:
- ""
- suppressing double quotes is feature request we have seen before, #1867
- the
cmd /c
workaround may work for extra encompassing double quotes, but not for quotes somewhere inside the commands
- \"
- the problem with executing
"notepad++ \"C:\\Work\\Test.txt\""
because of the\"
is separate issue- those quotes are not added by fzf, they were in the data and that has some consequences
- the
quoteEntryCmd
looks pretty solid, with one exception - it escapes double quotes with backslash, which is not very window-ish
- the problem with executing
I wrote some test cases ~~https://github.com/vovcacik/fzf/commit/67478d9219ab3ab93885b94fb36fe5f19c3a4f58~~ https://github.com/vovcacik/fzf/commit/100c86d689422b8256dc2d1c41a8ba0bd033181d
I confirm everything.
\"
the problem with executing
"notepad++ \"C:\\Work\\Test.txt\""
because of the\"
is separate issue
- those quotes are not added by fzf, they were in the data and that has some consequences
Yes, the command I wanted to run is:
notepad++ "C:\Work\Test.txt"
FZF manipulates that string in a way such that it is not possible to run the resulting command in the command prompt, as I described before.
@junegunn suggested a fix in https://github.com/junegunn/fzf/commit/c4185e81e86e339ae2c18e5d9b596b7992ec179b but I have no idea how I could compile/test it in Windows.
@junegunn I had some time to look at this. The problem with -n"12"
is probably just on Windows, but even there you would easily find programs that can handle this type of parameters (I suppose all Go programs can parse it properly) and vice versa.
All placeholders in fzf are treated as data and are escaped for that reason. This can limit usage on both platforms (e.g., fzf generated cat '~/test'
won't work, neither would cat '$HOME/test'
), but it is needed, because that data is often fed to programs that need proper escaping (grep, ripgrep).
On *nix you can probably use sh -c
, because it will easily understand the quotes and escaping. But cmd /c
has no clue about escaped double quotes \"
that fzf outputs (because it is sane thing to do with data and because ripgrep would require that kind of escaping).
But I didn't find anything in fzf that needs fixing and I am not sure if you would accept new functionality to deal with this kind of issues.
@pidgeon777 try type "Main.bat" | fzf.exe --delimiter="\t" --bind "enter:execute(type {f2}|cmd)"
it overcomes the lack of *.bat extension.
Some ideas for future work:
- whitelist some strings as safe and don't quote or escape them at all, e.g.
^\d+$
- #1867 maybe went too far; what if we drop the surrounding quotes and still escape content?
- the workaround on windows
type {f}|cmd
should probably be documented somewhere, equivalent tosh -c {f}
- dropping automatic quoting means some ugliness on command line,
fzf --bind "enter:execute(cmd /c \"{r2}\")"
(assumes "raw" flag being implemented) - https://github.com/junegunn/fzf/pull/2559#discussion_r722397203 would benefit from unquoted strings
I just wanted to add another Windows-specific use case which I think is related. In this case it is related to the Windows Registry which uses \
as a separator.
The command reg query HKCU
returns this on the command line:
HKEY_CURRENT_USER\AppEvents
HKEY_CURRENT_USER\Console
HKEY_CURRENT_USER\Control Panel
HKEY_CURRENT_USER\Environment
HKEY_CURRENT_USER\EUDC
HKEY_CURRENT_USER\Keyboard Layout
HKEY_CURRENT_USER\Microsoft
HKEY_CURRENT_USER\Network
HKEY_CURRENT_USER\Printers
HKEY_CURRENT_USER\SOFTWARE
HKEY_CURRENT_USER\System
HKEY_CURRENT_USER\Volatile Environment
But my silly and only slightly contrived script which I think should work:
reg query HKCU | fzf --reverse --bind "enter:reload(reg query {})"
results in:
[Command failed: reg query ^"HKEY_CURRENT_USER\\AppEvents^"]
The quotes do not cause an issue, but the doubled backslashes do.
Works: reg query "HKCU\Software"
Does not work : reg query HKCU\\Software
- reg
reports ERROR: Invalid key name
So a way to get raw strings could be handy sometimes on Windows.
Any update?
I second this. {n} outputs "text" on Windows and there's nothing you can do about it, which makes passing {2} to lots of programs useless (like SQLite, that treats double quoted strings as column names (there aren't any, of course)).
@cpkio yes I confirm this limitation, hopefully this will be fixed.
I dont know if this will help with any particular issue, but I was able to solve my problem with cmd /c for /f %i in ({2}) do @echo select
description from issues where number_in_project=%~i | sqlite3…
as fzf preview command. for
loop strips {2}
from quotes with %~i
and emits a string passed to stdin of sqlite, which luckily can accept stdin as sql command.