execute "normal! :echo ". system('echo hello')

The above results in:

E121: Undefined variable: hello 

Why? I'm expecting it to evaluate as:

  execute "normal! :echo hello"
  • I can reproduce this, though the chain of logic leads me to conclude with the OP that this is odd – D. Ben Knoble Apr 22 '20 at 22:52

There are a couple of problems here.

First of all, you want to run an ex command, so you don't need the :norm! command to execute an ex command. A simple :echo works. (In fact, you can and probably should get rid of the :exe command and use :echo directly, but I'll come back to this later).

Second, if you want to see what will be executed, use :echo instead of :exe. So this:

echo ":echo ". system('echo hello')

will output :echo hello. So what is the problem here? Have a look at the documentation at :h :echo

:ec[ho] {expr1} ..      Echoes each {expr1}, with a space in between.  The

Note the word expr1. So :echo expects an expression. What that means is, either a variable, or a quoted string (or some other special types like numbers, options, etc, see again the help at :h expression-syntax).

However, the way hello is used, :echo expects it to be a variable. But Vim cannot find a variable called hello, because it does not exist. So try this:

 :let g:hello='Hello my dear'
 :exe ':echo ' system('echo hello')
 Hello my dear

Note, since you are using string concatenation, to concatenate the output of the system() function with the :echo command. However, if you get rid of the indirection and simply use

:echo system('echo hello')

you can see directly the result of the echo system command. Because in this case, echo knows that the system('echo hello') command is a correct expression and it will simply output the result.

  • Is there some way I can quote / escape the value from system without having to use a intermediate variable? – Chris Stryczynski Apr 24 '20 at 7:52
  • You mean like this? exe ":echo ". string(system('echo hello')) But why keep this additional indirection? That sounds silly. – Christian Brabandt Apr 24 '20 at 8:38
  • Hmm, I should have explained that the echo 'hello' is just a placeholder / minimal example, instead I'm getting the output from a command that returns a filepath. – Chris Stryczynski Apr 24 '20 at 8:58
  • @ChrisStryczynski Understood. The question is more like: Why do you need :exe ":echo". Why not use :echo directly? – Christian Brabandt Apr 24 '20 at 9:01
  • 1
    @ChrisStryczynski :thoseCommands are technically VimScript commands. They can used as is, no need to put them into :exe calls. – Christian Brabandt Apr 24 '20 at 9:22

The bug is not in the first command, but in the second.

If you just run the Ex command directly, you get the same E121 error about undefined variable:

:echo hello
E121: Undefined variable: hello

So what's wrong with the second command? Well, you're missing a <CR> there to actually execute the command.

As :help :normal states:

{commands} should be a complete command. If {commands} does not finish a command, the last one will be aborted as if <Esc> or <C-C> was typed. This implies that an insert command must be completed. A ":" command must be completed as well.

You can reproduce the same error with:

:execute "normal! :echo hello\<CR>"
E121: Undefined variable: hello

This is actually equivalent to the command that uses system(), since system() will actually preserve the newline added by the echo command. You can see that with:

:echo strtrans(system('echo hello'))

(^@ is normally a NUL byte, but it's how Vim represents a newline internally. If you just :echo the result of that system() command you will notice a newline at the end, just it's not as visible as with strtrans() since it's, well, a newline.)

So all in all this error is expected, it's only omitted from your second example because that Ex command is being cancelled as it's incomplete.

  • These were my initial thoughts... oddly i concluded that concatenating the strings would work and i dont know why. Hm. – D. Ben Knoble Apr 23 '20 at 12: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.