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
Related
I have an rsync command that works as expected when I type it directly into a terminal. The command includes several --include='blah' and --exclude='foo' type arguments. However, if I save that command to a one-line file called "myfile" and I try `cat myfile` (or, equivalently $(cat myfile)), the rsync command behaves differently.
I'm sure it is the exact same command in both cases.
Is this behavior expected/explainable?
I've found the answer to this question. The point is that the cat command takes the contents of the file and treats it like a string. Any string operators (like the escape operator, ) are executed. Then, the final string output is what is passed to a command via the backticks.
As a solution, I've just made "myfile" a shell script that I can execute rather than trying to use cat.
I'm trying to write a simple script in tcsh (version 6.12.00 (Astron) 2002-07-23), but I am getting tripped up by the if-then-else syntax. I am very new to script writing.
This script works:
#!/bin/tcsh -f
if (1) echo "I disagree"
However, this one does not:
#!/bin/tcsh -f
if ( 1 ) then
echo "I disagree"
else
echo "I agree"
endif
For one thing, this code, when run, echoes both statements. It seems to me it should never see the else. For another, the output also intersperses those echoes with three iterations of ": Command not found."
Edited to add: here is the verbatim output:
: Command not found.
I disagree
: Command not found.
I agree
: Command not found.
I know that the standard advice is to use another shell instead, but I am not really in a position to do that (new job, new colleagues, everyone else uses tcsh, want my scripts to be portable).
When I copy-and-paste your script and run it on my system, it correctly prints I disagree.
When I change the line endings to Windows-style, I get:
: Command not found.
I disagree
: Command not found.
I agree
: Command not found.
So, your script very likely has Windows-style line endings. Fix the line endings, and it should work. The dos2unix command is one way to do that (man dos2unix first; unlike most UNIX text-processing commands, it replaces its input file.)
The problem is that tcsh doesn't recognize ^M ('\r') as an end-of-line character. It sees the then^M at the end of the line as a single command, and prints an error message then^M: Command not found. The ^M causes the cursor to return to the beginning of the line, and the rest of the message overwrite the then.
I have a third-party CLI program I downloaded using Node's package manager. This program is started by typing the name of the program in a terminal. Once you start the program, the program expects the user to enter strings of characters in which the program will interpret at proper commands if the strings of characters are those it recognizes. I want to automate the process of reading lines from a file, and passing these lines are strings of characters into the program.
Right now when I look up for help on Google for how to automate a CLI program, all I get it how to write a bash script. This is not enough, as what I need is a bash script that opens up a program and then passes arguments to that program, NOT to the terminal itself. Basically I need my script (which will take the file to read lines from as the only argument) to do the following
run my_program
while there are more lines to read from the file:
"Lookup"
$line
close my_program
where "Lookup" is a string of characters recognized as a command by my_program, and $line is meant to convey that I want to pass the line currently being read from the file as an argument to the program.
EDIT: I wrote the following script, but it's interpretting "while read line" as an argument to pass to my_program. How do I make it so that it only interprets the commands inside the while loop as arguments to my_program?
#!/bin/bash
while read line
do
my_program
"Lookup"
"$line"
done < $1
#!/bin/bash
while read line
do
my_program $line
done < $1
and run this script with input file as parameter
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'")
I have a number of files (more than a hundred) that I want to process using Vim. A sample of the files’ contents is as follows:
xyz.csv /home/user/mydocs/abc.txt
/home/user/waves/wav.wav , user_wav.wav
I want this to be replaced by:
xyz.csv /var/lib/mydir/abc.txt
/var/sounds/wav.wav , wav.wav
In each of the files, the changes I need to make are the same. My questions are:
Can I use Vim search and replace functionality by calling it from within a Bash script?
If so, how do I go about it?
P.S. I have searched StackOverflow for similar questions and found some answers using ex scripts, etc. I want to know how I can call an ex script from within a bash script.
While vim is quite powerful, this is not something I would normally use vim for. It can be done using a combination of common command line utilities instead.
I've assumed that the blank line in your example above is actually blank and does not contain spaces or any other whitespace characters. You can use the following to do what you want.
sed -e "s,/home/user/mydocs,/var/lib/mydir," -e "s,/home/user/waves,/var/sounds," -e "/^$/d" file1
You can use that command together with find and a for loop to do this for a bunch of files:
for file in `find . -maxdepth 1 -type f`
do
sed -e "s,/home/user/mydocs,/var/lib/mydir," -e "s,/home/user/waves,/var/sounds," -e "/^$/d" $file
done
In the for loop, the find command above limits the output to all files in the current directory (including dot files), assigning each line from the output of find to the file variable and then running the sed command posted earlier to transform the file the way you want it to be transformed.
This is how you'd invoke an ed script from bash:
ed filename <<END
/^$/d
%s|/home/user/mydocs|/var/lib/mydir|
%s|/home/user/waves|/var/sounds|
%s|, user_|, |
w
q
END
To answer with vim, you can do
vim -e 'bufdo!%s:\(xyz.csv \)/home/user/mydocs/\(abc.txt\n\)\n.*:\1/var/lib/mydir/\2/var/sounds/wav.wav , wav.wav:' -e 'xa' FILES
Note, I had assumed, that the second line is statically replaced, as it had looked like in the question.
If you don't like writing long lines in your script, you can create a file like:
s/FOO/BAR/
" several replacement and other commands
w " write the file
bd " if you want to
Then do:
vim -e "buffdo!source /your_scriptfile" -e "x" FILES
HTH
If all the editing consists in a series of substitutions, the most
idiomatic way of accomplishing it using Vim would be the following.
Open all the target files at once:
vim *.txt
Run the substitution commands on the loaded files:
:argdo %s#/home/user/mydocs#/var/lib/mydir#
:argdo %s#/home/user/waves#/var/sounds#
:argdo %s#, \zsuser_##
...
If changes are correctly made, save the files:
:wall
If the editing you want to automate could not be expressed only
in substitutions, record a macro and run it via the :normal
command:
:argdo norm!#z
(Here z is the name of the macro to be run.)
Lastly, if the editing should be performed from time to time and
needs to be stored in a script, try using the approach described
in the answer to a similar question.
Answer
While most vim users would be aware of the % motion command for executing inclusive commands on the whole document in the current buffer. Most modern versions of vim (ie 6.x+) support actions on regex searches for exclusive actions like so:
:/regex/substitute/match/replace/ # as vim command line
+"/reges/s/match/replace" # as bash cli parameter
This breaks down into vim doing the following,
search for regex and put the cursor at start of found point
call internal substitute function (see :help s or :help substitute) [ could be other commands ]
match string with regex for substitution
replace with new string value
Effectively it operates the same as the :global command.
Notes
Command after regex search can be any command, including '!"shell command"' filter commands.
Reference Help
:help global
:help substitute
:help filter