4

I have a file containing lines in below e.g. format -

[foo@host.com, bar@host.com], Payment processed - 23499, params = {'invoice':3243}

I only want the account numbers i.e. 23499. It's a number. Let's say it <account>. Its not a constant.

For that, I am trying to -

  1. Remove params ...
  2. Replace [...], from start of each line by whitespace

By ... I mean any string. I have tried -

# 1
:%s/params.*//g
# 2
:%s/\<[]\>//g
:%s/\<\[\]\>//g
:%s/\<[.*]\>//g
:%s/\<\[.*\]\>//g

All the things I have tried in # 2 have not worked. What am I doing wrong? How do I get <account>? Help me out.

  • 1
    It seems that there has been serious confusion for what you actually want the output to be. Given the example input you mention, what would your desired output look like? – HalosGhost Sep 25 '14 at 17:00
  • Coul it be that there is a comma missing in "2."? I had read "from start of each line by whitespace" as something with a whitespace separator. But with a comma, it's pretty clear: "Replace [...], from start of each line, by whitespace." – Volker Siegel Sep 25 '14 at 17:03
  • 23499. 23500. 36754. 43266 and so on. Account numbers from email subject – Hussain Tamboli Sep 25 '14 at 17:04
  • And no whitespace in front of them? – Lieven Keersmaekers Sep 25 '14 at 17:52
  • Each number on newline. I couldn't type a newline in the comment :( – Hussain Tamboli Sep 25 '14 at 18:16
2

You can use following sequence to only retain the account numbers (cudo's to J.D.Mohr)
note the space after the r in the command

:%norm $F,d$Bhv0r 

This assumes that there's only one , after the number you want to retain

Breakdown

:     -> Enter command mode
%norm -> Applies a normal command to the entire file
$     -> Jump to end of line
F,    -> Find preceding ,
d$    -> Delete until end of line
B     -> Jump back a word
hv0   -> Go left one character and select until beginning of line
r     -> replace selected text with <space>
  • 1
    @HalosGhost - The idea is to type the entire sequence on the line and hit return. – Lieven Keersmaekers Sep 25 '14 at 16:17
  • This is close, but doesn't quite do what was asked for. They wanted whitespace in place of the junk at the beginning of the line. :%norm $F,d$Bhv0r works for me (with an impotant space at the end there). – talkloud Sep 25 '14 at 16:17
  • @J.D.Mohr - I missed that, tx for the correction. – Lieven Keersmaekers Sep 25 '14 at 16:19
  • Yes i am able to remove [emails]. But the solution seems little difficult. Whats wrong with the things i have tried in #2? – Hussain Tamboli Sep 25 '14 at 16:49
  • @HussainTamboli - You are not searching for anything in your first two regexes and the last two are greedy. Try /\v^.{-}\d+ as regex and work from there. The {-}is not greedy as opposed to *. The ^ is to start from the beginning of the line and the \d+ is a number followed by other numbers. – Lieven Keersmaekers Sep 25 '14 at 17:49
0

To get only the <account> string

awk '{print $6}' file| sed 's/,//' >> newfile

For possible future usage of the main data, this could be useful

  • 1
    I imagine this could be done with awk alone. It certainly doesn't need the pipe from cat, at least. – HalosGhost Sep 25 '14 at 15:33
  • @HalosGhost You're correct – tachomi Sep 25 '14 at 15:35
  • I would prefer if i get the solution in vim – Hussain Tamboli Sep 25 '14 at 16:46
0

If you would look for <account> (something like <12345>) and have have < and > only in <account>, as it looked like in the original version of the question, then this could work:

%s/\v.*(\<.*\>).*/\1/

It matches < and > with anything between - which is in a group, and anything before and after in the line. That is replaced by just the group.

Answering the updated question:

If you do not have <account>, but a number in this place, with no < and >: this works in a similar way:

%s/\v.* - ([0-9]*), params =.*/\1/

It matches numbers, in a group to keep them. And it matches anything before that ends with " - ", and anything after that starts with , params =, both up to start or end of line.
So the expression matches the whole line, and is replaced by the matched group that contains the number.

It's using \v for "very magic" regular expressions see :help /magic.

  • Hi, I am really sorry I created a confusion. I don't have < and >. In fact <account> is a number. – Hussain Tamboli Sep 25 '14 at 15:22
  • 1
    Oh, you should edit the question! – Volker Siegel Sep 25 '14 at 15:22
  • But , params = is actually , params = , and ` - ` is ` - `? – Volker Siegel Sep 25 '14 at 15:24
  • If I am able to remove emails it will be great (emails are put in []). I will easily be able to get the account numbers. – Hussain Tamboli Sep 25 '14 at 16:11
  • The update in the second part of my answer should already output the number only. – Volker Siegel Sep 25 '14 at 16:12
0

As easy as it might be to want to use vim (or sed for this), awk is actually entirely capable of doing this type of matching and substitution all on its own:

$ awk '{ sub(/^.* - /, ""); sub(/,.*$/, ""); print $0 }' file
23499

The above matches everything (with awk's built-in sub() function) from the beginning of the line to the hyphen and space before the account number and replaces it with the empty string "". Then, it matches everything from the comma to the end of the line and replaces it with the empty string. This should robustly (e.g., regardless of how many emails or what their formatting might be) remove everything but the account number.

If you have access to gawk, then you can use a simpler solution (only one function call needed):

$ gawk 'match($0, /^.* - ([0-9]+),.*$/, a) { print a[1] }' file
23499

Of course, the above solutions print the new data to stdout. If you wanted to save the new data for use later, all you would need to do is add > newfile to the end of the above command (note, that > overwrites; if you would prefer appending, you can use >>).

awk has many limitations of its own (for example, working with many files at the same time), so it's not always the best tool for this type of manipulation. However, it is quite good at what it does, so when your use-case lines up with its round-house, I'd strongly recommend using it.

In addition, the above solution requires no interactive interface (like vim) and no piping.

  • How can I replace emails by whitespace? Emails are put in [] – Hussain Tamboli Sep 25 '14 at 16:08
  • you see I can easily remove some part from the lines using Visual mode. vim is just a preference. – Hussain Tamboli Sep 25 '14 at 16:21
  • Ahh, I think I misread your question; you were wanting the all the leadup information to be padded with spaces, rather than completely removed? Do you want it padded with spaces equal to character count? Do you want the [] to remain? – HalosGhost Sep 25 '14 at 16:22
  • No i want to remove emails and the [] brackets that contain those emails – Hussain Tamboli Sep 25 '14 at 16:41
  • I added another solution that uses two sub() calls; the first matches everything up to the closing ] and the comma and space that follows and replaces it with the empty string. The second removes everything after the account field. – HalosGhost Sep 25 '14 at 16:49

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.