unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
From: MBR <mbr@arlsoft.com>
To: C K Kashyap <ckkashyap@gmail.com>
Cc: help-gnu-emacs@gnu.org
Subject: Re: Emacs equivalent of the ":g" command in vi
Date: Fri, 22 Jul 2011 16:27:44 -0400	[thread overview]
Message-ID: <4E29DD40.80909@arlsoft.com> (raw)
In-Reply-To: <CAGdT1gpcY+Tz_5df0AE3eMvw-zJAD_3Se4aE8o_a5joRV=2Ubw@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 6136 bytes --]

On 7/22/2011 4:42 AM, C K Kashyap wrote:
> Hi,
> Could someone please tell me how I could go about something like this -
> I need to perform a certain action (such as delete the line) on each 
> line of a buffer if the line matches a regular expression. In vim, we 
> can use the :g command for this.
> Regards,
> Kashyap

I looked for the same thing ages ago when I switched from vi to emacs.  
Eventually I figured out that:

    :g/regular expression/operation

reflects an 'ed' mindset, and that an Emacs macro with a repeat count is 
actually far more powerful .  (In case you're wondering what 'ed' is, it 
was the original, line-oriented, Unix editor.  'vi' was Bill Joy's 
visual mode version of 'ex', which was his enhanced version of 'ed'.)

An Emacs macro is a series of emacs commands that you can replay.  You 
use C-( and C-) as follows to create a macro:

    C-(
    type any commands you want Emacs to remember
    C-)

Then, whenever you type C-x e, Emacs will replay the commands.

At this point, you're probably wondering how this can substitute for 
vi's g//.  Simple.  Just start your macro off with a regular expression 
search, do whatever you want, and then replay it multiple times with:

    C-u /count/ C-x e

Specify a large enough repeat count, and you can make your macro apply 
to the whole file.

For example, to delete each line of a buffer if the line matches a 
regular expression, you'd define the macro with:

    C-(            ;; Begin recording macro
    C-M-s regexp    ;; Search for regular expression
    C-a            ;; Go to beginning of line
    C-k             ;; Kill one line by typing C-k twice
    C-k            ;;
    C-)            ;; End recording macro

Then you'd execute the macro with:

    C-u 10000 C-x e

Of course, there's an easier way to delete lines that match a regular 
expression:

    M-x delete-matching-lines

But you described the general problem as needing to perform a certain 
action on each line of a buffer if the line matches a regular 
expression.  And the approach of defining a macro to do what you want 
and then executing it with a large repeat count gives you a general 
purpose mechanism to do arbitrary operations rather than just delete the 
line.

For example, if I have a file of lines of the format:

    zip,street address,city,state,phone,name

That I wanted to rearrange to:

    name,phone,street address,city,state,zip

I could run:

    M-x replace-regexp
    ^\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\)$
    \6,\5,\2,\3,\4,\1

which is the equivalent of vi's:

    :g/^\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\)$/s//\6,\5,\2,\3,\4,\1/g

But making sure you've got that regular expression right can be tricky.  
It can be much easier to just do it with emacs commands applied to a 
single line.  Although the following is difficult to read, I think if 
you try it out you'll find it pretty straightforward.  First fill an 
emacs buffer with lots of lines of the form:

    name,phone,street address,city,state,zip

Then type these emacs keystrokes (omitting the comments):

    ;; Begin recording macro
    C-(
    ;; Narrow the buffer to the current line:
    C-SPC C-n C-x n n M-<
    ;; Move the part after the fifth ","
    ;; to the beginning of the line
    C-s , C-s C-s C-s C-s C-b C-k C-a C-y , C-a C-d
    ;; Move the part that's now after the fifth ","
    ;; to the second comma-delimited position
    C-s , 4*C-s C-b C-k C-a M-f C-y
    ;; Move the third comma-delimited part to the end
    M-d C-e C-y
    ;; Move forward over the newline to the next line
    C-f
    ;; Widen so you can see the whole buffer
    C-x n w
    ;; End recording macro
    C-)

Replay it 10,000 times with:

    C-u 10000 C-x e

It will stop as soon as it runs out of matching lines.

The point is that the operations you can repeat this way are limited 
only by your imagination.

There's a variant of this that I use frequently.  I often find that a 
non-emacs application wants me to type lots of information into 
individual fields of an input screen.  It's a pain to have to type all 
that data, especially when I have that data in a text file.  In emacs I 
can organize the data into the same order as the input fields in the 
application, putting each field's data on a separate line of the emacs 
buffer.  Then I do the following in emacs:

    ;; Begin recording macro
    C-(
    ;; Mark region from beginning to end of line
    C-aC-SPCC-e
    ;; Copy region so it can be pasted into another application
    C-w
    ;; Move forward over the newline to the next line
    C-f
    ;; End recording macro
    C-)

Once I've defined that macro, I can repeatedly type:

    ;; This is not an Emacs command.  It tells the window manager
    ;; to give keyboard focus to the other application.
    ALT-TAB
    ;; Paste into the input field
    C-v
    ;; Move focus to the next input field
    TAB
    ;; Give keyboard focus to Emacs.
    ALT-TAB
    ;; Repeat the macro, which copies the next line.
    C-x e

At that point, I repeatedly type:

    C-x e ALT-TAB C-v TAB ALT-TAB

While it's not fully automated, If I've got lots of data that has to be 
entered through a GUI interface, it makes things go a whole lot faster.

If you should want to save a macro you've created this way so you can 
use it in future Emacs sessions:

    Open your .emacs file: C-x C-f ~/.emacs
    Give it a name by with:M-x name-last-kbd-macro
    Insert it into your .emacs with: M-x insert-kbd-macro
    Save your .emacs file: C-x C-s

                Mark Rosenthal
                mbr@arlsoft.com <mailto:mbr@arlsoft.com>

P.S. - Interesting side-note.  Did you know that the ed command:

     g/regular expression/operation

is where the name "grep" came from?  In ed and ex, the "g" means do a 
global search for the immediately following regular expression, and 
apply the operation to every matching line.  One such operation is "p" 
meaning "print".  Using "re" as shorthand for "regular expression", the 
ed command to print every line that matches a particular regular 
expression is:

                 g/re/p



[-- Attachment #2: Type: text/html, Size: 8969 bytes --]

  parent reply	other threads:[~2011-07-22 20:27 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-07-22  8:42 Emacs equivalent of the ":g" command in vi C K Kashyap
2011-07-22  9:27 ` Peter Dyballa
2011-07-22  9:48   ` Thierry Volpiatto
2011-07-22 10:02     ` C K Kashyap
2011-07-22 10:12       ` Peter Dyballa
2011-07-22 10:41         ` C K Kashyap
2011-07-22 10:34       ` Thien-Thi Nguyen
2011-07-22 10:44         ` C K Kashyap
2011-07-22 10:45       ` Deniz Dogan
2011-07-22 10:46         ` Deniz Dogan
2011-07-22 19:03       ` Eric Abrahamsen
2011-07-22 20:27 ` MBR [this message]
2011-07-22 20:37   ` Andreas Röhler
2011-07-22 20:51     ` MBR
2011-07-23  7:10       ` Andreas Röhler
2011-08-15  0:27       ` Ken Goldman
2011-07-23  3:02   ` C K Kashyap
2011-07-23  8:44     ` suvayu ali

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4E29DD40.80909@arlsoft.com \
    --to=mbr@arlsoft.com \
    --cc=ckkashyap@gmail.com \
    --cc=help-gnu-emacs@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).