0

I have a file that reads similar to this:

random_string
83: some words 45: large error report 326: send emails to certain peple
random_string
34: some words 143: job success

I want to target the pattern "#:" (a number followed by a colon) and add a new line after the text that follows it; so it reads like this:

random_string
83: some words
45: large error report
326: email certain people

random_string
34: some words
143: job success

I've tried a sed commands of:

sed "s#'([0-9]*[0-9]:)'#a '/n'#" file.txt
sed "s#'([0-9]*[0-9]:)'#\n#g" file.txt

(I don't like using slashes as delimiters, the fence posts make it hard to read)

and an awk command of:

awk '/[0-9]*[0-9]:/ {printf "%s\n",$0}' file.txt

And neither have worked. I've looked at similar problems posted here and tried their solutions but nothing has worked. I know the answer is most likely very similar and it may even have something to do with the syntax in my number expression but I can't figure it out myself. I have no preference to either awk or sed but I think they would be the best tools at my disposal.

Help?

  • 1
    Hi and welcome to the site! For help on formatting your posts see our help page on formatting tools. – terdon Jul 27 '17 at 15:20
  • Thanks, and sorry. I knew it looked wonky but I wasn't sure what to do with it. I pinned the link I'm sure it will come in handy. – cdruckemiller Jul 27 '17 at 15:23
  • No reason to apologize, we were all new once! Now, please edit your question to ensure that your desired output is correct. Do you really want those blank lines? And your output doesn't match your description. Why do you have a FILENAME as the first line? There's only one FILENAME in your input. And how can we know where the filename (if that's what it is) ends? For instance, 83: xyz has a space after the xyz, is that part of the name or should it be removed? Can the file name have numbers in it? – terdon Jul 27 '17 at 15:25
  • How does the random string looks like? – John Goofy Jul 27 '17 at 15:30
1

Here's a Perl solution:

$ perl -pe 's/(\d+:.*?)(?=\d+:|$)/$1\n/g' file
random_string
83: some words 
45: large error report 
326: send emails to certain peple

random_string
34: some words 
143: job success

Explanation

  • (\d+:.*?) : match one or more numbers (\d+) followed by a :, and then the smallest string (the ? in .*? makes it non-greedy, it will stop as soon as the first match is found) matching the rest of the regex. Here, it will continue until the part explained below.
  • (?=\d+:|$) : The (?=foo) is called a positive lookahead. It will match but what is matched will not be included in the actual result. So, bar(?=foo) will match all cases of bar that are followed by foo. Here, we are looking for either a string of numbers followed by an : (\d+:) or the end of the line ($).

Now, the substitution operator will replace all occurrences of the first pattern with itself and a newline which should give you the desired output.

  • @cdruckemiller you're welcome. I added a (rather limited) explanation of the regex as well. – terdon Jul 27 '17 at 15:47
  • You could make it perl -pe 's/(\d+:.*?)\h*(?=\d+:|$)/$1\n/g' to strip the blanks in between the records (or at the end of the line) – Stéphane Chazelas Aug 3 '17 at 14:49
0
$ cat file
random_string
83: some words 45: large error report 326: send emails to certain peple
random_string
34: some words 143: job success

You can use sed:

$ sed 's/[0-9]*: [a-z ]*/&\n/g' file

Output:

random_string
83: some words 
45: large error report 
326: send emails to certain peple

random_string
34: some words 
143: job success
  • This sed command seems to take every word after my target puts it on a new line. I just want a new line to be created before every target input. This is probably, again, my fault for not being clear in the question, and I will edit it again for clairity. – cdruckemiller Jul 27 '17 at 15:36
  • @cdruckemiller You are right, try to post reliable input, code effort and output. Otherwise we just have to guess. – John Goofy Jul 27 '17 at 15:39
0

awk seems to do the trick:

$ awk '{ for( i=1; i<=NF; i++ ) { if( match( $i, ":" ) ) { printf "\n" } printf( "%s ", $i ) } }' /path/to/file
random_string
83: some words
45: large error report
326: email certain people random_string
34: some words
143: job success
0

Comparing your input to your output, it seems as if your description of what you want is incorrect. You say "I want to target the pattern #: (a number followed by a colon) and add a new line after" when a more accurate description would be:

  • replace the space before any number of digits followed by a colon with a newline.
  • insert a newline before every non-empty line not beginning with a digit.
  • skip the first line of input because there's nothing that needs to be changed on it.

This sed script implements that. It uses extended regular expressions (-E) instead of sed's default basic regex to minimise the number of backslash escapes required and improve readability.

$ sed -E -e '2,$ {s/ ([0-9]+:)/\n\1/g; s/^[^0-9]/\n&/}' file.txt
random_string
83: some words
45: large error report
326: send emails to certain peple

random_string
34: some words
143: job success

BTW, if there's a possibility of tabs rather than spaces before the [0-9]+:, or multiple whitespace characters then use [[:space:]]+ instead of just a space. e.g.

sed -E -e '2,$ {s/[[:space:]]+([0-9]+:)/\n\1/g; s/^[^0-9]/\n&/}' file.txt

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.