How to execute yanked multi line command in shell within vim - shell

I have the following curl command in a file.
curl \
--request POST \
https://oauth2.googleapis.com/tokeninfo?id_token=eyJhbGci
How do I execute the command in bash/zsh shell within vim?
I tried to do :!<C-r>" (Ctrl + r then ") but it says
zsh:1: no match found: https://oauth2.googleapis.com/tokeninfo?id_token=eyJhbGci
shell returned 1

? is a glob character, zsh is looking for a file named http://oauth2.googleapis.com/tokeninfo + a single character + id_token=eyJhbGci and reporting that there are no matches.
Escape or quote it, any one of
https://oauth2.googleapis.com/tokeninfo\?id_token=eyJhbGci
'https://oauth2.googleapis.com/tokeninfo?id_token=eyJhbGci'
"https://oauth2.googleapis.com/tokeninfo?id_token=eyJhbGci"
or use setopt +o nomatch to make zsh behave like the default in other shells (if no matches, continue with the argument untouched).
Preferably just quote it.

Alternatively, you can use :help :w_c to pass arbitrary lines to an external command.
Select three lines and execute via sh:
vjj
:'<,'>w !sh
Execute current line:
:.w !sh
Execute whole buffer:
:%w !sh
Execute given range:
:12,34w !sh
See :help :range.

Related

KSH: How to escape backslash and double quotes together

I can't force KSH to pass \" as a parameter to command.
What I want to be executed LITERALLY is:
command \"foo bar\"
Below examples are executed in ksh with set -x executed beforehand to display the echo of each command in the exact format in which it would be executed (after it is parsed by ksh)
[oracle#localhost sf_vm]$ ksh
$ set -x
What I tried and got is:
$ command \"foo bar\"
+ command '"foo' 'bar"'
not what I need: missing \ and additional ' and "
$ command \\\"foo bar\\\"
+ command '\"foo' 'bar\"'
no luck again: additional ' outside and between foo and bar
$ command "\\\"foo bar\\\""
+ command '\"foo bar\"'
almost right but still unwanted ' on the outside
$ command '\"foo bar\"'
+ command '\"foo bar\"'
again almost right but still ' on the outside
The actual use case is that I'm passing USERID parameter to oracle expdb command in format of
expdp USERID=/ AS SYSDBA which needs to be enclosed in escaped double quotes like so:
expdp USERID=\"/ AS SYSDBA\"
I know I can workaround this by using a prm file for expdp but it's very inconvenient in my case (automated export)
I'm using ksh93 version if that makes any difference:
[oracle#localhost sf_vm]$ ll /etc/alternatives/ksh
lrwxrwxrwx. 1 root root 10 Oct 15 2018 /etc/alternatives/ksh -> /bin/ksh93
Let's start from your use case.
The following command, which you assert works
expdp USERID=\"/ AS SYSDBA\"
evaluates to a rather unintuitive argument list, as you can see below (note that this particular code only works for argument lists that don't contain literal newlines anywhere):
$ printf '%s\n' expdp USERID=\"/ AS SYSDBA\" | jq -Rnc '[inputs]'
["expdp","USERID=\"/","AS","SYSDBA\""]
...which is to say, you're passing expdp three arguments beyond the 0th/first one: USERID="/ is the first argument, AS is the second argument, and SYSDBA" is the third argument. The shell is correct when its set -x implementation prints this argument list as expdp 'USERID="/' AS 'SYSDBA"', as that argument list eval's identically to the above.
Frankly, I doubt very much that this is actually correct/intended usage for any tool. It would make more sense if your backslashes weren't escaped, and your intended usage were instead expdp USERID="/ AS SYSDBA", which would evaluate to (in JSON syntax) ["expdp", "USERID=/ AS SYSDBA"].
Ok, thanks to your comments about the set -x which I did interpreted wrongly I got it actually working with command \"foo bar\" besides what the set output would suggest it correctly passes the "foo bar" enclosed with brackets as a command paramater.
As it turned out my actual issue was the syntax in the parameter value itself.
For future reference following expdp command syntax is correct in ksh when value begin passed has spaces (in this case userid as sysdba):
expdp USERID=\"sys/password#SID as sysdba\" DIRECTORY=EXPDP DUMPFILE=HR.COUNTRIES.dmp TABLES=HR.COUNTRIES ...

aix ksh : how to quit the vi command line editor wirthout actually executing the command?

In ksh, when you are in vi mode, you can invoke the vi editor by using ESC+v.
Then, vi is launched, and you can use it to edit the command you were working on.
The problem is that, whatever how you quit the editor (:q!, ...), it seems the command will always be executed. Is there a trick for this not to happen ?
My only solution so far is to delete the whole command then exit with :q!
When your command is a oneliner, you can Insert a # at the first position.
When you have more lines, you do not want to comment all lines.
Enter return above the first line (use O) and the rest will be ignored. Do not use exit, than you will exit your shell.
EDIT:
As #Henk pointed out in the comments, the trick with return will fail with a real ksh shell. I tested set -o vi in bash and things are different there.
Just typing ggdGZZ would be quicker, but here are two options:
Option 1, quotes
Insert : ' at the top and a single quote ' at the end:
: '
more
than
one
line
'
Swap single quotes for double quotes if necessary.
Option 2, force a syntax error
Insert : followed by an unset variable reference, triggering a syntax error:
: ${nil:?}
more
than
one
line
"/tmp/ast38.kia" [converted] 5L, 33C written
: ${nil:?}
more
than
one
line
/bin/ksh: hist: line 1: nil: parameter not set
$

How to write a multi line macro in ~/.lldbinit?

I want to write this macro in ~/.lldbinit:
command regex pxml 's/(.+)/p xmlElemDump(stdout, %1, xmlDocGetRootElement(%1))/' -h "Dump the contents of an XML tree."
But it is too long and I want to break it into multi lines like this:
command regex pxml
's/(.+)/p xmlElemDump(stdout, %1, xmlDocGetRootElement(%1))/'
-h "Dump the contents of an XML tree."
or
command regex pxml\
's/(.+)/p xmlElemDump(stdout, %1, xmlDocGetRootElement(%1))/'\
-h "Dump the contents of an XML tree."
Unfortunately both of them cause this error:
Enter one of more sed substitution commands in the form: 's/<regex>/<subst>/'.
Terminate the substitution list with an empty line.
How can I break the macro into multi lines?
lldb doesn't have a continuation character. That would be tricky in some of the free-form commands, particularly the "print" command. But would be useful in these cases. Feel free to file a bug requesting this with the lldb/llvm bug tracker: https://llvm.org/bugs/.
In most cases where a command has a few options, then takes a set of inputs, the command can enter a little mini-editor for the set of inputs. This is true for command regex. So in command line lldb, you would see:
(lldb) command regex whatever -h "some help" -s "some syntax"
Enter one of more sed substitution commands in the form: 's/<regex>/<subst>/'.
Terminate the substitution list with an empty line.
> s/First/Replacement/
> s/Second/Replacement/
>
The command source function that also reads the .lldbinit works by feeding the command file as a stream to the interpreter. So you need to mock up what the command line does:
command regex whatever -h "some help" -s "some syntax"
s/First/Replacement/
s/Second/Replacement/
That's not quite right, there has to be a blank line in the input file after the last substitution to terminate the substitutions, but I can't convince this markup to include it in the code block. But you get the idea.
I write aliases in a .py file and import it to ~/.lldbinit.
In python file, we can use continuation character.
e.g.)
you would save the following code as something.py
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand("command regex pos 's/(.*)?-op?(.*)/ exp -l swift -O %2 -- %1/'\
's/(.*)/ exp -l swift -O -- %1/'")
write this in ~/.lldbinit
command script import <path>/something.py

How can I use the output of an external command as an argument to tabnew?

In my .bashrc, I have the following short script to get the current date.
D(){ date +'%F'; }
In my .vimrc, I have the following two lines to make it so that I can use this function.
set shell=bash\ --login
set shellcmdflag=-ic
I have tested that the function works in vim, by verifying that the following command puts the current date into the buffer.
:r !D
However, what I would like to do is to use the output of this bash function as an argument to tabnew so I can open a file named by the current date in a new tab.
:tabnew !D
Unfortunately, the behavior of this command is to create a new tab with the literal filename !D isntead of the output.
How can I get the output of the external command as an argument to tabnew instead?
Backtick expansion can be used to insert the output of external commands in Vim commands, generally as arguments:
:tabnew `date +'\%F'`
or:
:tabnew `D`
See :help backtick-expansion.

Pass argument with newline to external commands in vim

When I'm interacting with the shell or writing a bash script I can do:
somecmd "some
arg"
Say now that I want to do the same in vim command-line mode:
:!somecmd "some<Enter>arg"
obviously won't work: as soon as I press <Enter> the command is executed. But neither the following do:
:!somecmd "some<C-V><Enter>arg"
:!somecmd "some<C-V>x0Aarg"
The first one inserts a carriage return instead of a line feed, which is right. The second one will break the command in two, trying to execute somecmd "some<C-V> first and then arg", both of which fail miserably.
I guess I could work around this using some echo -e command substitution, or embedding $'\n', but is it possible to type it directly in vim's command-line? I don't fully understand why the "some<C-V>x0Aarg" form doesn't work while $'some\narg' does. Is vim parsing the string previously to shell evaluation?
Well, I've found the answer myself, but I'm leaving here for further reference anyway. The documentation of :! states:
A newline character ends {cmd}, what follows is interpreted as a following ":" command. However, if there is a backslash before the newline it is removed and {cmd} continues. It doesn't matter how many backslashes are before the newline, only one is removed.
So you (I) should type "some\<C-V>x0Aarg" instead of "some<C-V>x0Aarg".
Plus, I could have done it using the system() function instead of the :! command:
:call system("somecmd 'some<C-V>x0Aarg'")

Resources