C0ppert0p
C0ppert0p

Reputation: 702

Concatenating lines with sed based on the length of a line

Essentially, I want to read a file and concatenate each line to the next line, only if the first line has a length of less than 6. (Six is the maximum length of a chapter "number".)

16.
Chapter Name
17.
Chapter Name 
Appendix
A.1.
Appendix name
A.2.
Appendix name

In this example the output would be:

16. Chapter name
17. Chapter Name 
Appendix
A.1. Appendix name
A.2. Appendix name

Using this:

sed 'N;s/\n/ /'

results in:

16. Chapter Name
17. Chapter Name 
Appendix A.1.
Appendix name A.2.
Appendix name    

Does sed support the use of logic to move a line to the hold buffer based on its length (or if it fits a pattern)?

Would awk be a better option?

Upvotes: 0

Views: 211

Answers (5)

Claes Wikner
Claes Wikner

Reputation: 1517

awk 'sub(/\.$/,". "){printf $0;next}1' file

16. Chapter Name
17. Chapter Name 
Appendix
A.1. Appendix name
A.2. Appendix name

Upvotes: 0

Sundeep
Sundeep

Reputation: 23667

Another sed solution

$ sed -E '/^.{,5}$/{N; s/\n/ /}' ip.txt 
16. Chapter Name
17. Chapter Name 
Appendix
A.1. Appendix name
A.2. Appendix name
  • /^.{,5}$/ if line has maximum of 5 characters
    • N; get next line
    • s/\n/ / substitute the first \n with space
  • Some sed versions use -r instead of -E for extended regex


And another perl solution

$ perl -lpe '$_ .= " ".<> if length() < 6; chomp' ip.txt 
16. Chapter Name
17. Chapter Name 
Appendix
A.1. Appendix name
A.2. Appendix name
  • $_ contains the current line
  • $_ .= " ".<> if length() < 6 append space and next line if current line is less than 6 characters
  • chomp remove ending new line character if present from $_. Required because the next line obtained by <> would have \n character
  • -l option removes ending \n from input lines and adds it back while printing
  • -p iterate over input files in a loop, $_ value is printed by default at end of all commands

Upvotes: 1

Chris Koknat
Chris Koknat

Reputation: 3451

If Perl is an option:

perl -pe 'chomp; $_.=(length()<6?" ":"\n")' file

chomp removes the newline
$_ is the current line
The ternary ? : operator either appends a space or a newline

Upvotes: 0

Benjamin W.
Benjamin W.

Reputation: 52142

With sed:

$ sed -r 'N;/^(.){,5}\n/s/\n/ /;P;D' infile 
16. Chapter Name
17. Chapter Name 
Appendix
A.1. Appendix name
A.2. Appendix name
  • Extended regexes (-r) are just used so I didn't have to type \(.\)\{,5\}.
  • N;P;D creates a moving two-line window: N appends the next line to the pattern space, P prints the first line of the pattern space, and D deletes it.
  • /^(.){,5}\n/ matches if the pattern space contains five or fewer characters before the newline
  • If this matches, s/\n/ / concatenates the two lines

The hold space isn't required for this, but if it were, you could copy the pattern space based on its length with the same regex as used here.

Upvotes: 1

James Brown
James Brown

Reputation: 37404

In awk:

$ awk '{printf "%s", $0 (length($0)<6?" ":ORS)}' foo
16. Chapter Name
17. Chapter Name
Appendix
A.1. Appendix name
A.2. Appendix name

Upvotes: 1

Related Questions