0

Let's say we have a text file with 1000 lines.

How can we delete new line characters from line 20 to 500 (replace them with space for example)?

My try:

sed '20,500p; N; s/\n/ /;' #better not to say anything

All other lines (1-19 && 501-1000) should be preserved as-is.

As I'm familiar with sed, awk or perl solutions are welcomed, but please give an explanation with them as I'm a perl and awk newbie.

i alarmed alien
  • 9,412
  • 3
  • 27
  • 40
josifoski
  • 1,696
  • 1
  • 14
  • 19
  • possible duplicate of [sed: How can I replace a newline (\n)?](http://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n) –  Sep 20 '14 at 09:48
  • 1
    @Evert not too sure about that, the question is about replacing _every_ newline in a file, not just the ones within a range. – Tom Fenech Sep 20 '14 at 09:55

4 Answers4

3

You could use something like this (my example is on a slightly smaller scale :-)

$ cat file
1
2
3
4
5
6
7
8
9
10
$ awk '{printf "%s%s", $0, (2<=NR&&NR<=5?FS:RS)}' file
1
2 3 4 5 6
7
8
9
10

The second %s in the printf format specifier is replaced by either the Field Separator (a space by default) or the Record Separator (a newline) depending on whether the Record Number is within the range.

Alternatively:

$ awk '{ORS=(2<=NR&&NR<=5?FS:RS)}1' file
1
2 3 4 5 6
7
8
9
10

Change the Output Record Separator depending on the line number and print every line.

You can pass variables for the start and end if you want, using awk -v start=2 -v end=5 '...'

Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
  • 1
    I've used second example & it's working which is most important tnx! – josifoski Sep 20 '14 at 10:09
  • 1
    @josifoski a program that produces the expected output is the starting point for a solution. Consider how you'd enhance this script to do something trivial like printing the input line number before every output value (just change `printf "%s%s", $0,...` to `printf "%s %s%s", NR, $0,...` in that first example or change `1` to `{print NR, $0}` in that 2nd example). Now consider how you'd modify the sed solution you selected to do the same. sed is simply not the right tool for anything other than simple substitutions on a single line. – Ed Morton Sep 20 '14 at 15:28
2

This might work for you (GNU sed):

sed -r '20,500{N;s/^(.*)(\n)/\2\1 /;D}' file

or perhaps more readably:

sed ':a;20,500{N;s/\n/ /;ta}' file
potong
  • 55,640
  • 6
  • 51
  • 83
  • Missing single quote at the end of the second example? – Tom Fenech Sep 20 '14 at 13:11
  • also missing \\( before braces, however, I've choosed this one only because sed is mentioned. Struggling myself to learn sed, or awk or perl. For now seding :) – josifoski Sep 20 '14 at 13:13
  • 1
    @josifoski sed is an excellent tool for simple substitutions on a single line, it's useful commands are s, g, and p (with -n). All of it's other language constructs became obsolete in the mid-1970s when awk was invented. I would strongly recommend you use the posted awk solution for this and any other problems that involve processing multiple lines of input simultaneously and don't bother trying to learn/use all of the other sed language constructs because the awk alternative is always more robust, portable, extensible, maintainable, clearer, usually faster and often briefer. – Ed Morton Sep 20 '14 at 15:14
  • 1
    @ed-morton tnx for advice! – josifoski Sep 20 '14 at 15:28
  • 1
    @josifoski You're welcome. Dont get me wrong, I use sed almost daily and it's great for what it's best at and I'm sure in the early 1970s when it was the only alternative to `ed` all of those constructs to do things with multiple lines were very useful but that was a LONG time ago! I'd recommend you get the book Effective Awk Programming, Third Edition, by Arnold Robbins if you're going to be doing any but the most trivial text processing. – Ed Morton Sep 20 '14 at 15:37
1

Here's a perl version:

my $min = 5; my $max = 10;
while (<DATA>) {
    if ($. > $min && $. < $max) {
        chomp;
        $_ .= " ";
    }
    print;
}

__DATA__
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Output:

1
2
3
4
5
6 7 8 9 10
11
12
13
14
15

It reads in DATA (which you can set to being a filehandle or whatever your application requires), and checks the line number, $.. While the line number is between $min and $max, the line ending is chomped off and a space added to the end of the line; otherwise, the line is printed as-is.

i alarmed alien
  • 9,412
  • 3
  • 27
  • 40
  • `$_` is a "default" variable -- for a number of different functions, you don't need to specify a named variable (e.g. `$i`); you can use this default variable. If you do want to refer to it, you can use `$_`. In this case, `$_` is the current line of `__DATA__` that we're looking at. [More information in perlvar](http://perldoc.perl.org/perlvar.html#General-Variables). `.=` means append to string; in this case, we're appending a space to the current line. – i alarmed alien Sep 20 '14 at 15:29
1

Using a perl one-liner to strip the newline:

perl -i -pe 'chomp if 20..500' file

Or to replace it with a space:

perl -i -pe 's/\R/ / if 20..500' file

Explanation:

Switches:

  • -i: Edit <> files in place (makes backup if extension supplied)
  • -p: Creates a while(<>){...; print} loop for each “line” in your input file.
  • -e: Tells perl to execute the code on command line.

Code:

  • chomp: Remove new line
  • 20 .. 500: if Range operator .. is between line numbers 20 to 500
Miller
  • 34,962
  • 4
  • 39
  • 60
  • Starting good book for perl programming, specially parsing? @miller – josifoski Sep 20 '14 at 18:07
  • Whether one is an experienced Perl programmer or a beginner, the first resource I'd probably point one to is: [Modern Perl Book by chromatic](http://modernperlbooks.com/). It teaches one not just how to write Perl, but how to write it well, and is available free online. – Miller Sep 20 '14 at 18:19