0

According to the documentation for shellescape in vim:

shellescape({string}, [, {special}])      shell escape()

Escape {string} for use as a shell command argument.
...
For other systems, it will enclose {string} in single quotes and replace all "'" with "'\''".

Is there a function that will escape the same characters for the shell without enclosing {string} in single quotes?

  • I'm curious why you would need this? – Martin Tournoij Jan 10 '17 at 21:27
  • 1
    You could use shellescape and then strip them out with substitute. – Tumbler41 Jan 10 '17 at 22:01
  • @Carpetsmoker I noticed from the earlier question (vi.stackexchange.com/questions/10851/…) when I ran the command from inside vim, that it would put single quotes around the argument passed to my node.js script...and that the script didn't work properly when the quotes were passed. – leeand00 Jan 10 '17 at 22:05
  • 4
    The problem with using shellescape() and then removing the quotes is that you're no longer escaping anything :-) This may be a problem down the line if you have arguments with spaces in them and the like. I suspect that the problem is that you're passing two or more arguments to shellescape? (e.g something like shellescape(a:argA . ' ' . a:argB)? You should call it for every argument: shellescape(a:argA) . ' ' . shellescape(a:argB) – Martin Tournoij Jan 10 '17 at 22:21
  • 1
    Could you post an example of your system() call in addition to your use of shellescape()? @Carpetsmoker is more than likely right that you're running shellescape() on your entire argument list instead of on individual arguments. The only other issue I've encountered with shellescape() is when escaping an argument that already has an escaped ', such as JSON strings. – Tommy A Jan 11 '17 at 4:52
1

A very long time ago, long before shellescape(), and I don't remember if escape() existed at that time, I wrote a function with the aim of running external commands from vim. Now it's shipped with my lh-vim-lib library, on vim.org we may find a trace of it in my system-tools set of scripts.

Any way, I copy-paste its documentation and its code, I can't tell whether it'll be of any help to you, you'll have to check.

The doc.

                                                *lh#path#fix()*                   {{{3
lh#path#fix({pathname} [,{shellslash} [,{quote-char}]]~
Discl.: This function is the old |system-tools|' |FixPathName| moved to lh-vim-lib.

This function corrects the {a:pathname} passed in parameter and, returns the
newly fixed pathname that will be usable will external tools.

Under Windows boxes, it will build the new path according to the value of
{shellslash}. Under other systems, the new path will be exclusively composed of
forward slashes. According to {quote-char}, quote characters may be added around
the returned pathname.

For instance, paths like "`c:\Program Files/alongpath/some\ spaces/foo`" will be
changed into: >
    c:\Program Files\alongpath\some spaces\foo   + {quote-char} around
 or c:/Program\ Files/alongpath/some\ spaces/foo + {quote-char} around
according to {shellslash} value.

Internal considerations~
    {quote-char} will value the character:
        1- {a:quote-char} if given,
        2- "" (empty string) otherwise.
    {shellslash} will value the boolean:
        1- {a:shellslash} if given
        2- 'shellslash' if win16, win32, dos16 or dos32
                    and if |SystemDetected()| != "msdos"
        3- 1 if |SystemDetected()| == "unix"
    if {quote-char}=="" && !{shellslash} && |SystemDetected()|=="`msdos`"
        if 'shell' == "`command.com`" => {quote-char} <- ''
        else                        => {quote-char} <- '"'

Note: If you are using "`command.com`" (and not cmd.exe which is available on
MsWindows NT series), you may run into troubles if the {a:pathname} contains
spaces.

Exemples~
    This mapping opens the current file in MsWindows's files explorer
    [Note: this works if the 'shell' is bash or $COMSPEC]: >
        nmap ,view :exe '!start explorer '.lh#path#fix(expand('%:p'),0)<cr>

Note: Unlike |fnameescape()|, |lh#path#fix()| will work even under the Windows native flavour of gvim, whichever the |'shellslash'| is, and whichever the |'shell'| is.

The code.

" Function: lh#path#fix(pathname [, shellslash [, quote_char ]]) {{{3
" This function was FixEnsurePath from system_tools
function! lh#path#fix(pathname, ...) abort
  " Parameters       {{{4
  " Ignore the last slash or backslash character, if any
  let pathname   = matchstr(a:pathname, '^.*[^/\\]')
  " Default value for the quote character
  let quote_char = ''
  " Determine if 'shellslash' exists (dos-like platforms)
  if lh#os#OnDOSWindows()
    if lh#os#system_detected() == 'msdos'
      let shellslash = 0
    else
      let shellslash = &shellslash
    endif
  else "unix
    let shellslash = 1
  endif
  " Determine if we will use slashes or backslashes to distinguish directories
  if a:0 >= 1   "
    let shellslash = a:1
    if a:0 >= 2
      let quote_char = a:2
    endif
  endif

  " Smart definition of quote chars for $COMSPEC
  if (lh#os#system_detected() == 'msdos') && !shellslash && (''==quote_char)
    if (&shell =~ 'command\.com')
      if pathname =~ ' '
        " should also test long directory-names...
        " Best: AVOID command.com !!!
        if &verbose >= 1
          call lh#common#error_msg('lh#path#fix: '.
                \ 'Problem expected because of the space in <'.pathname.'>')
        endif
      else
        let quote_char = ''
      endif
    else
      let quote_char = '"'
    endif
  endif

  " Fix the pathname {{{4
  if shellslash
    " return substitute(dname, '\\\([^ ]\|$\)', '/\1', 'g')
    let res = substitute(
          \ substitute(pathname, '\\\([^ ]\|$\)', '/\1', 'g'),
          \ '\(^\|[^\\]\) ', '\1\\ ', 'g')
  else
    " return substitute(
          " \ substitute(pathname, '\([^\\]\) ', '\1\\ ', 'g'),
          " \ '/', '\\', 'g')
    let res = substitute(
          \ substitute(pathname, '\\ ', ' ', 'g'),
          \ '/', '\\', 'g')
  endif
  " Note: problem to take care (that explains the complex substition schemes):
  " sometimes the path passed to the function mix the two writtings, e.g.:
  " "c:\Program Files/longpath/some\ spaces/foo"
  " }}}4
  return quote_char . res . quote_char
endfunction

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.