0

The log viewing experience is so bad in my current company. I want to add new line to the logs that I've trimmed for a specific time duration. I want a new line after every date-time.

The date-time format is like this.

2023-10-03 15:34:37

I am aware tr can do this but I'm not sure how. I'll select the answer best anyone who can tell me how to write that new to a new file. Because of performance reasons. I don't prefer using vi, I use less as a logs reader.

2 Answers 2

2

In vim, you could do:

:%s/\v^\d{4}(-\d{2}){2} \d{2}(:\d{2}){2}.*/&\r

Note the \v for very magic so you don't need to add backslashes before every {}().

Yes, \r in the replacement adds a newline (splits the line in two using the wording at :help s/\r), not a carriage return as one might have expected.

In standard vi (\d, \v, \r, norm being all vim extensions), the equivalent would look like:

:%s/^[[:digit:]]\{4\}\(-[[:digit:]]\{2\}\)\{2\} [[:digit:]]\{2\}\(:[[:digit:]]\{2\}\)\{2\}.*/&^M/

Where the ^M is entered by pressing Ctrl+V followed by Enter (and again inserts a LF aka newline aka ^J, not CR aka carriage-return aka ^M).

But the vi implementation on CentOS is vim (and has been since at least as far back as CentOS 4) so you should be able to rely on the vim extensions in vi there.

In any case tr is a tool to transliterate, replace characters with other characters or delete or squeeze them, it cannot be used here.

sed, awk or perl could be used (AFAIK, \d as a regex operator originated in perl):

perl -pi -e '$_ .= "\n" if /^\d{4}(-\d{2}){2} \d{2}(:\d{2}){2}/' your-file

To edit the file in place. Or:

perl -p -e '$_ .= "\n" if /^\d{4}(-\d{2}){2} \d{2}(:\d{2}){2}/' < your-file > new-file

To get the result into a new file.

Or here, provided the Regex::Common::time module is available:

perl -MRegexp::Common=time -p -e '
  $_ .= "\n" if m{^$RE{time}{strftime}{-pat=>"%Y-%m-%d %H:%M:%S"}}
  ' < your-file > new-file

Which will do a stricter matching (not match on 2023-13-00 25:61:62 for instance). There's also a $RE{time}{iso} which will match those dates, but also many other variants of ISO8601 dates including some without date or time component, so can't be used here.

You can see the actual regex with:

$ perl -MRegexp::Common=time -le 'print $RE{time}{strftime}{-pat=>"%Y-%m-%d %H:%M:%S"}'
(?:(?:\d{4})-(?:(?:(?=[01])(?:0[1-9]|1[012])))-(?:(?:(?=[0123])(?:0[1-9]|[12]\d|3[01]))) (?:(?:(?=[012])(?:[01]\d|2[0123]))):(?:(?:[0-5]\d)):(?:(?:(?=[0-6])(?:[0-5]\d|6[01]))))
10
  • I want to save it to a new file.
    – achhainsan
    Commented Oct 10, 2023 at 8:19
  • @achhainsan then just remove the i option for perl and redirect the output or use :saveas in vim Commented Oct 10, 2023 at 8:21
  • perl isn't very common in indian servers.
    – achhainsan
    Commented Oct 10, 2023 at 8:55
  • @StéphaneChazelas you are one of the best VIM users out there. You helped me and a lot of others many many times before. Just wanted to say thanks for that and also wanted to ask if my solution is correct too / can be vimproved? :)
    – Bog
    Commented Oct 10, 2023 at 9:54
  • @Pixelbog. Thanks. I'm far from being a vim expert. Your answer looks fine except. 1) I'd clarify (like in mine) that it's vim specific 2) anchor the regex at the start of the line 3) (nitpick) maybe note that it moves the cursor. Commented Oct 10, 2023 at 10:00
1

This Command:

Press : and enter g/\v\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/normal o

Explanation:

  • g: short for global, executes a command on all lines that match a regex
  • \v: Makes the regex 'very magic' (actual name of it). Means that you don't have to escape special characters
  • /^\d\{4\}-\d\{2\}-\d\{2\} \d\{2\}:\d\{2\}:\d\{2\}/: is the regex. Put it into a tool like https://regexr.com/ or https://regex101.com/, they explain it really good
  • normal o: normal command executes arguments in normal mode. In that case it presses o which opens a new line


Read explanations from the Official Documentation: :help global, :help \v, :help normal

5
  • "later" never comes. :D
    – achhainsan
    Commented Oct 10, 2023 at 7:10
  • By later I mean in around 7 hours. Have a really busy day sorry^^ But here rlly quick: g is the command, everything between the first and second / is a regex to match your time format and the norm command executes the o as it would be in normal mode. Sorry again^^
    – Bog
    Commented Oct 10, 2023 at 9:52
  • 1
    @achhainsan There you go, there is your (hopefully) good explanation :))
    – Bog
    Commented Oct 10, 2023 at 11:08
  • @Chris Davies Should I create a new question for doing it in either less(if possible) or on command line to convert and save to a new file?
    – achhainsan
    Commented Oct 11, 2023 at 2:42
  • I assume you know how to do that already. I was trying to point out that stating the requirement, lifting the restrictions, and showing what you've tried is better than statng the issue and saying it must be done with tools X and Y. Unless there really is a very definite reason for using tools X and Y, of course Commented Oct 11, 2023 at 7:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .