Fru*_*uit 8 vim filenames quoting
假设我用这个创建了一个文件名:
xb@dnxb:/tmp/test$ touch '"i'"'"'m noob.mp4"'
xb@dnxb:/tmp/test$ ls -1
"i'm noob.mp4"
xb@dnxb:/tmp/test$
Run Code Online (Sandbox Code Playgroud)
然后vim .
进入 Netrw 目录列表。
" ============================================================================
" Netrw Directory Listing (netrw v156)
" /tmp/test
" Sorted by name
" Sort sequence: [\/]$,\<core\%(\.\d\+\)\=\>,\.h$,\.c$,\.cpp$,\~\=\*$,*,\.o$,\.obj$,\.info$,\.swp$,\.bak$,\~$
" Quick Help: <F1>:help -:go up dir D:delete R:rename s:sort-by x:special
" ==============================================================================
../
./
"i'm noob.mp4"
Run Code Online (Sandbox Code Playgroud)
然后按Enter查看文件。类型:
:!ls -l %
Run Code Online (Sandbox Code Playgroud)
它会显示错误:
xb@dnxb:/tmp/test$ vim .
ls: cannot access '/tmp/test/i'\''m noob.mp4': No such file or directory
shell returned 2
Press ENTER or type command to continue
Run Code Online (Sandbox Code Playgroud)
我也试过:
[1] :!ls -l '%'
:
Press ENTER or type command to continue
/bin/bash: -c: line 0: unexpected EOF while looking for matching `"'
/bin/bash: -c: line 1: syntax error: unexpected end of file
shell returned 1
Press ENTER or type command to continue
Run Code Online (Sandbox Code Playgroud)
[2] :!ls -l "%"
:
Press ENTER or type command to continue
/bin/bash: -c: line 0: unexpected EOF while looking for matching `''
/bin/bash: -c: line 1: syntax error: unexpected end of file
shell returned 1
Press ENTER or type command to continue
Run Code Online (Sandbox Code Playgroud)
[3] :!ls -l expand("%")
:
/bin/bash: -c: line 0: syntax error near unexpected token `('
/bin/bash: -c: line 0: `ls -l expand(""i'm noob.mp4"")'
shell returned 1
Press ENTER or type command to continue
Run Code Online (Sandbox Code Playgroud)
[4] !ls -l shellescape("%")
:
/bin/bash: -c: line 0: syntax error near unexpected token `('
/bin/bash: -c: line 0: `ls -l shellescape("/tmp/test/"i'm noob.mp4"")'
shell returned 1
Press ENTER or type command to continue
Run Code Online (Sandbox Code Playgroud)
[5] !ls -l shellescape(expand("%"))
:
/bin/bash: -c: line 0: syntax error near unexpected token `('
/bin/bash: -c: line 0: `ls -l shellescape(expand("/tmp/test/"i'm noob.mp4""))'
shell returned 1
Press ENTER or type command to continue
Run Code Online (Sandbox Code Playgroud)
我的最终目标是rsync
通过Ctrl+执行c,例如:
nnoremap <C-c> :!eval `ssh-agent -s`; ssh-add; rsync -azvb --no-t % xiaobai@127.0.0.1:/home/xiaobai/storage/
Run Code Online (Sandbox Code Playgroud)
我的平台是 Kali Linux 的vim.gtk3
bash。Fedora的vim
和gvim
也有同样的问题。
在 vim 中转义包含单引号和双引号的文件名的正确语法是什么?
[更新]
exec '!ls -l' shellescape(expand('%'))
可以工作,但我不知道如何使rsync
上述工作。我不知道我应该在哪里为这个更复杂的命令加上引号rsync
。
小智 6
使用文件名修饰符以通配符的答案为基础,:S
为您提供您想要的。根据文档 ( :h %:S
),
:S Escape special characters for use with a shell command (see
|shellescape()|). Must be the last one. Examples:
:!dir <cfile>:S
:call system('chmod +w -- ' . expand('%:S'))
Run Code Online (Sandbox Code Playgroud)
使用您的示例:
$ touch '"I'\''m also a n00b.txt"'
$ ls
"I'm also a n00b.txt"
Run Code Online (Sandbox Code Playgroud)
然后vim '"I'\''m also a n00b.txt"'
,瞧:
:!ls %:S
"I'm also a n00b.txt"
Run Code Online (Sandbox Code Playgroud)
该:S
文件名修改是在Vim的7.4可用。
从:help filename-modifiers
:
The file name modifiers can be used after "%", "#", "#n", "<cfile>", "<sfile>",
"<afile>" or "<abuf>". ...
...
:s?pat?sub?
Substitute the first occurrence of "pat" with "sub". This
works like the |:s| command. "pat" is a regular expression.
Any character can be used for '?', but it must not occur in
"pat" or "sub".
After this, the previous modifiers can be used again. For
example ":p", to make a full path after the substitution.
:gs?pat?sub?
Substitute all occurrences of "path" with "sub". Otherwise
this works like ":s".
Run Code Online (Sandbox Code Playgroud)
因此,我们不只是处理双引号或单引号,而是用反斜杠转义所有不寻常的内容:
:!ls -l %:gs/[^0-9a-zA-Z_-]/\\&/
Run Code Online (Sandbox Code Playgroud)
与您提供的测试文件名完美配合。
要使用您可能需要的绝对路径,您可以在末尾rsync
添加::p
:!ls -l %:gs/[^0-9a-zA-Z_-]/\\&/:p
Run Code Online (Sandbox Code Playgroud)
实际上,如果您对每个字符进行反斜杠转义,它也可以正常工作,并且键入的时间会更短:
:!ls -l %:gs/./\\&/:p
Run Code Online (Sandbox Code Playgroud)
因此,在您的rsync
命令中,请使用 ,而不是。%
%:gs/./\\&/:p