3

I am trying to define a string in vimscript containing a literal # which then gets passed to a shell command using execute.

function! g:Call_imagemagick_with_hex(hex_color)
    let a:display_command = "! display -size 300x300 xc: '\#" . a:hex_color . "'"
    execute a:display_command
    "echo(a:display_command)
endfunction

and I would call this function like

:call Call_imagemagick_with_hex('34495e')

what I want the shell to see via execute' is:

display -size 300x300 xc: '#34495e'

The problem is that if # appears unescaped in the string passed to execute, vim tries to expand it - it seems # is like % but represents the previous buffer. e.g. If I use

let a:display_command = "! display -size 300x300 xc: '#" . a:hex_color . "'"

vim tries to expand # and throws an error. If I use

let a:display_command = "! display -size 300x300 xc: '\#" . a:hex_color . "'"

the shell sees:

display -size 300x300 xc: '\#34495e'

and the shell command doesn't work. From learning vimscript the hardway

Using single quotes tells Vim that you want the string exactly as-is, with no escape sequences. The one exception is that two single quotes in a row will produce one single quote.

It seems if ' does protects against meta-character expansion, it's possibly only in certain contexts.
Otherwise, how can I pass a # character to an underlying shell command?

  • @user9433424 thanks, the shellescape() looks interesting. I tried your command and it seems to work from the point of dealing with the # thanks – the_velour_fog May 17 '16 at 11:10
  • Did you try \\#? See :help string. – romainl May 17 '16 at 11:40
  • @romainl I did think to try that but dimissed the idea because I thought it would only add characters. Im interested to to see what it does though . I will try now... – the_velour_fog May 17 '16 at 11:42
  • @romainl it seems the first "\" is getting consumed by vim. i.e. when I xtrace what the shell is seeing I get + display -size 300x300 'xc:\#59a7da'. I'm still confused by this issue. it seems like vim's user interface, vimscript seems modal too, i.e. the rules about when metacharacters are escaped depends on the command using the string... – the_velour_fog May 17 '16 at 11:55
  • :execute "!echo \\\\#" or :execute '!echo \\#. – romainl May 17 '16 at 12:10
4

You should use system instead of execute ! :

call system("display -size 300x300 xc: '#" . a:hex_color . "'")

You can use the return value in a variable if you want, e.g.:

let l:files = system('ls')

In this case you can prefer using the systemlist() that returns a list:

let l:files = systemlist('ls')

If you need to use special vim char in this context you can always use expand.

Reference: :h system()

  • thanks, I needed to use call system(...) else vim threw an error. the # doesn't seem to be making it to the display command. also the shell command display doesnt have a text output. it launches an x gui program. Still testing now.. – the_velour_fog May 17 '16 at 10:47
  • even if I run call system('display -size 300x300 xc: "#34495e"') the display command isn't working as expected. – the_velour_fog May 17 '16 at 10:55
  • what is your issue ? can you try with a simpler command (i.e. ls/cat/..) to check if the issue is your command ? – nobe4 May 17 '16 at 10:56
  • 1
    xtrace is showing that vim seems to invoking the command perfectly + display -size 300x300 xc: '#34495e' it seems your system idea is working, the problem now must be somewhere else. I think this solves the # issue anyway. thanks – the_velour_fog May 17 '16 at 11:04
  • 1
    turns out it was a space between xc: # causing the problem! so this version of your statement: call system('display -size 300x300 xc:"#' . a:hex_color . '"') works fine. – the_velour_fog May 17 '16 at 11:23

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.