Remove lines from a file

From Rosetta Code
Jump to: navigation, search
Task
Remove lines from a file
You are encouraged to solve this task according to the task description, using any language you may know.

The task is to demonstrate how to remove a specific line or a number of lines from a file. This should be implemented as a routine that takes three parameters (filename, starting line, and the number of lines to be removed). For the purpose of this task, line numbers and the number of lines start at one, so to remove the first two lines from the file foobar.txt, the parameters should be: foobar.txt, 1, 2

Empty lines are considered and should still be counted, and if the specified line is empty, it should still be removed. An appropriate message should appear if an attempt is made to remove lines beyond the end of the file.

Contents

[edit] Ada

with Ada.Text_IO, Ada.Directories, Ada.Command_Line, Ada.IO_Exceptions;
use Ada.Text_IO;
 
procedure Remove_Lines_From_File is
Temporary: constant String := ".tmp";
begin
if Ada.Command_Line.Argument_Count /= 3 then
raise Constraint_Error;
end if;
declare
Filename: String := Ada.Command_Line.Argument(1);
First: Positive := Integer'Value(Ada.Command_Line.Argument(2));
Last: Natural := Integer'Value(Ada.Command_Line.Argument(3)) + First - 1;
Input, Output: File_Type;
Line_Number: Positive := 1;
begin
Open(Input, In_File, Filename); -- open original file for reading
Create(Output, Out_File, Filename & Temporary); -- write to temp. file
while not End_Of_File(Input) loop
declare
Line: String := Get_Line(Input);
begin
if Line_Number < First or else Line_Number > Last then
Put_Line(Output, Line);
end if;
end;
Line_Number := Line_Number + 1;
end loop;
Close(Input);
Close(Output);
Ada.Directories.Rename(Old_Name => Filename & Temporary,
New_Name => Filename);
end;
exception
when Constraint_Error | Ada.IO_Exceptions.Name_Error =>
Put_Line("usage: " & Ada.Command_Line.Command_Name &
" <filename> <first> <length>");
Put_Line(" opens <filename> for reading and " &
"<filename>" & Temporary & " for temporary writing");
Put_Line(" requires first > 0, length >= 0");
end Remove_Lines_From_File;

[edit] AutoHotkey

RemoveLines(filename, startingLine, numOfLines){
Loop, Read, %filename%
if ( A_Index < StartingLine )
|| ( A_Index >= StartingLine + numOfLines )
ret .= "`r`n" . A_LoopReadLine
FileDelete, % FileName
FileAppend, % SubStr(ret, 3), % FileName
}
 
SetWorkingDir, % A_ScriptDir
RemoveLines("test.txt", 4, 3)
Output

with test.txt starting as

1
2
3
4
5
6
7
8

Running the code it is now

1
2
3
7
8

[edit] AWK

 
# syntax: GAWK -f REMOVE_LINES_FROM_A_FILE.AWK
# show files after lines are removed:
# GAWK "FNR==1{print(FILENAME)};{print(FNR,$0)}" TEST1 TEST2 TEST3
BEGIN {
build_test_data()
remove_lines("TEST0",1,1)
remove_lines("TEST1",3,4)
remove_lines("TEST2",9,3)
remove_lines("TEST3",11,1)
exit(errors+0)
}
function build_test_data( fn,i,j) { # create 3 files with 10 lines each
for (i=1; i<=3; i++) {
fn = "TEST" i
for (j=1; j<=10; j++) {
printf("line %d\n",j) >fn
}
close(fn)
}
}
function remove_lines(fn,start,number_of_lines, arr,fnr,i,n,rec,stop) {
stop = start + number_of_lines - 1
while (getline rec <fn > 0) { # read file
fnr++
if (fnr < start || fnr > stop) {
arr[++n] = rec
}
}
close(fn)
if (fnr == 0) {
printf("error: file %s not found\n",fn)
errors = 1
return
}
for (i=1; i<=n; i++) { # write file
printf("%s\n",arr[i]) >fn
}
close(fn)
if (stop > fnr) {
printf("error: file %s trying to remove nonexistent lines\n",fn)
errors = 1
}
}
 

[edit] C

#include <stdio.h>
#include <stdlib.h> /* for atoi() and malloc() */
#include <string.h> /* for memmove() */
 
/* Conveniently print to standard error and exit nonzero. */
#define ERROR(fmt, arg) return fprintf(stderr, fmt "\n", arg)
 
int main(int argc, char **argv)
{
FILE *fp;
char *buf;
size_t sz;
int start, count, lines = 1;
int dest = 0, src = 0, pos = -1;
 
/* Initialization and sanity checks */
if (argc != 4)
ERROR("Usage: %s <file> <start> <count>", argv[0]);
 
if ((count = atoi(argv[3])) < 1) /* We're a no-op. */
return 0;
 
if ((start = atoi(argv[2])) < 1)
ERROR("Error: <start> (%d) must be positive", start);
 
if ((fp = fopen(argv[1], "r")) == NULL)
ERROR("No such file: %s", argv[1]);
 
/* Determine filesize and allocate a buffer accordingly. */
fseek(fp, 0, SEEK_END);
sz = ftell(fp);
buf = malloc(sz + 1);
rewind(fp);
 
/* Fill the buffer, count lines, and remember a few important offsets. */
while ((buf[++pos] = fgetc(fp)) != EOF) {
if (buf[pos] == '\n') {
++lines;
if (lines == start) dest = pos + 1;
if (lines == start + count) src = pos + 1;
}
}
 
/* We've been asked to do something weird; clean up and bail. */
if (start + count > lines) {
free(buf);
fclose(fp);
ERROR("Error: invalid parameters for file with %d lines", --lines);
}
 
/* Overwrite the lines to be deleted with the survivors. */
memmove(buf + dest, buf + src, pos - src);
 
/* Reopen the file and write back just enough of the buffer. */
freopen(argv[1], "w", fp);
fwrite(buf, pos - src + dest, 1, fp);
 
free(buf);
fclose(fp);
return 0;
}

[edit] C++

#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>
#include <list>
 
void deleteLines( const std::string & , int , int ) ;
 
int main( int argc, char * argv[ ] ) {
if ( argc != 4 ) {
std::cerr << "Error! Invoke with <deletelines filename startline skipnumber>!\n" ;
return 1 ;
}
std::string filename( argv[ 1 ] ) ;
int startfrom = atoi( argv[ 2 ] ) ;
int howmany = atoi( argv[ 3 ] ) ;
deleteLines ( filename , startfrom , howmany ) ;
return 0 ;
}
 
void deleteLines( const std::string & filename , int start , int skip ) {
std::ifstream infile( filename.c_str( ) , std::ios::in ) ;
if ( infile.is_open( ) ) {
std::string line ;
std::list<std::string> filelines ;
while ( infile ) {
getline( infile , line ) ;
filelines.push_back( line ) ;
}
infile.close( ) ;
if ( start > filelines.size( ) ) {
std::cerr << "Error! Starting to delete lines past the end of the file!\n" ;
return ;
}
if ( ( start + skip ) > filelines.size( ) ) {
std::cerr << "Error! Trying to delete lines past the end of the file!\n" ;
return ;
}
std::list<std::string>::iterator deletebegin = filelines.begin( ) , deleteend ;
for ( int i = 1 ; i < start ; i++ )
deletebegin++ ;
deleteend = deletebegin ;
for( int i = 0 ; i < skip ; i++ )
deleteend++ ;
filelines.erase( deletebegin , deleteend ) ;
std::ofstream outfile( filename.c_str( ) , std::ios::out | std::ios::trunc ) ;
if ( outfile.is_open( ) ) {
for ( std::list<std::string>::const_iterator sli = filelines.begin( ) ;
sli != filelines.end( ) ; sli++ )
outfile << *sli << "\n" ;
}
outfile.close( ) ;
}
else {
std::cerr << "Error! Could not find file " << filename << " !\n" ;
return ;
}
}


[edit] Common Lisp

(defun remove-lines (filename start num)
(let ((tmp-filename (concatenate 'string filename ".tmp"))
(lines-omitted 0))
;; Open a temp file to write the result to
(with-open-file (out tmp-filename
:direction :output
:if-exists :supersede
:if-does-not-exist :create)
;; Open the original file for reading
(with-open-file (in filename)
(loop
for line = (read-line in nil 'eof)
for i from 1
until (eql line 'eof)
;; Write the line to temp file if it is not in the omitted range
do (if (or (< i start)
(>= i (+ start num)))
(write-line line out)
(setf lines-omitted (1+ lines-omitted))))))
;; Swap in the temp file for the original
(delete-file filename)
(rename-file tmp-filename filename)
;; Warn if line removal went past the end of the file
(when (< lines-omitted num)
(warn "End of file reached with only ~d lines removed." lines-omitted))))

[edit] D

import std.stdio, std.file, std.string;
 
void main() {
deleteLines("deleteline_test.txt", 1, 2);
}
 
void deleteLines(string name, int start, int num)
in {
assert(start > 0, "Line counting must start at 1");
} body {
start--;
 
if (!exists(name) || !isFile(name))
throw new FileException("File not found");
 
auto lines = readText(name).splitLines();
if (lines.length < start + num)
throw new Exception("Can't delete lines past the end of file!");
 
auto f = File(name, "w");
foreach (int i, line; lines) {
if (start > i || i >= start + num)
f.writeln(line);
}
}

[edit] F#

open System
open System.IO
 
let cutOut (arr : 'a[]) from n = // confine syntax highlighting confusion'
let slicer = fun i -> if i < from || (from + n) <= i then Some(arr.[i-1]) else None
((Array.choose slicer [| 1 .. arr.Length |]), from + n - arr.Length > 1)
 
[<EntryPoint>]
let main argv =
let nums = Array.choose (System.Int32.TryParse >> function | true, v -> Some v | false, _ -> None) argv.[1..2]
let lines = File.ReadAllLines(argv.[0])
let (sliced, tooShort) = cutOut lines nums.[0] nums.[1]
if tooShort then Console.Error.WriteLine "Not enough lines"
File.WriteAllLines(argv.[0], sliced)
0

Output

D:\Projects\Rosetta>for /l %i in (1,1,5) do @echo %i >> foo
 
D:\Projects\Rosetta>Remove_lines_from_a_file.exe foo 1 2
 
D:\Projects\Rosetta>type foo
3
4
5
 
D:\Projects\Rosetta>

[edit] Go

package main
 
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
)
 
func main() {
if err := removeLines("foobar.txt", 1, 2); err != nil {
fmt.Println(err)
}
}
 
func removeLines(fn string, start, n int) (err error) {
if start < 1 {
return errors.New("invalid request. line numbers start at 1.")
}
if n < 0 {
return errors.New("invalid request. negative number to remove.")
}
var f *os.File
if f, err = os.OpenFile(fn, os.O_RDWR, 0); err != nil {
return
}
defer func() {
if cErr := f.Close(); err == nil {
err = cErr
}
}()
var b []byte
if b, err = ioutil.ReadAll(f); err != nil {
return
}
cut, ok := skip(b, start-1)
if !ok {
return fmt.Errorf("less than %d lines", start)
}
if n == 0 {
return nil
}
tail, ok := skip(cut, n)
if !ok {
return fmt.Errorf("less than %d lines after line %d", n, start)
}
t := int64(len(b) - len(cut))
if err = f.Truncate(t); err != nil {
return
}
if len(tail) > 0 {
_, err = f.WriteAt(tail, t)
}
return
}
 
func skip(b []byte, n int) ([]byte, bool) {
for ; n > 0; n-- {
if len(b) == 0 {
return nil, false
}
x := bytes.IndexByte(b, '\n')
if x < 0 {
x = len(b)
} else {
x++
}
b = b[x:]
}
return b, true
}

[edit] Haskell

import System.Environment (getArgs)
 
main = getArgs >>= (\[a, b, c] ->
do contents <- fmap lines $ readFile a
let b1 = read b :: Int
c1 = read c :: Int
putStr $ unlines $ concat [take (b1 - 1) contents, drop c1 $ drop b1 contents]
)

[edit] Icon and Unicon

procedure main() # remove lines
removelines("foo.bar",3,2) | stop("Failed to remove lines.")
end
 
procedure removelines(fn,start,skip)
 
f := open(fn,"r") | fail # open to read
every put(F := [],|read(f)) # file to list
close(f)
 
if *F < start-1+skip then fail
every F[start - 1 + (1 to skip)] := &null # mark delete
 
f := open(fn,"w") | fail # open to rewrite
every write(\!F) # write non-nulls
close(f)
return # done
end

[edit] J

removeLines=:4 :0
'count start'=. x
file=. boxxopen y
lines=. <;.2]1!:1 file
(;lines {~ <<< (start-1)+i.count) 1!:2 file
)

Thus:

$ cal >cal.txt
$ cat cal.txt
July 2011
Su Mo Tu We Th Fr Sa
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
  2 1 removeLines 'cal.txt'
$ cat cal.txt
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

Note that this code assumes that the last character in the file is the line end character.

[edit] Java

 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
 
public class RemoveLines
{
public static void main(String[] args)
{
//Enter name of the file here
String filename="foobar.txt";
//Enter starting line here
int startline=1;
//Enter number of lines here.
int numlines=2;
 
RemoveLines now=new RemoveLines();
now.delete(filename,startline,numlines);
}
void delete(String filename, int startline, int numlines)
{
try
{
BufferedReader br=new BufferedReader(new FileReader(filename));
 
//String buffer to store contents of the file
StringBuffer sb=new StringBuffer("");
 
//Keep track of the line number
int linenumber=1;
String line;
 
while((line=br.readLine())!=null)
{
//Store each valid line in the string buffer
if(linenumber<startline||linenumber>=startline+numlines)
sb.append(line+"\n");
linenumber++;
}
if(startline+numlines>linenumber)
System.out.println("End of file reached.");
br.close();
 
FileWriter fw=new FileWriter(new File(filename));
//Write entire string buffer into the file
fw.write(sb.toString());
fw.close();
}
catch (Exception e)
{
System.out.println("Something went horribly wrong: "+e.getMessage());
}
}
}
 
 

[edit] Liberty BASIC

It's always a bit dangerous to experiment with code that alters files. Un-rem the 'kill' to remove the temp file and the next line so the file is renamed to the original!

 
call removeLines "foobar.txt", 1, 2
end
 
sub removeLines filename$, start, count
open filename$ for input as #in
open filename$ + ".tmp" for output as #out
lineCounter = 1
firstAfterIgnored = start + count
while not(eof(#in))
line input #in, s$
if lineCounter < start or lineCounter >= firstAfterIgnored then
print #out, s$
end if
lineCounter = lineCounter + 1
wend
close #in
close #out
'kill filename$
'name filename$ + ".tmp" as filename$
end sub
 

[edit] Lua

function remove( filename, starting_line, num_lines )
local fp = io.open( filename, "r" )
if fp == nil then return nil end
 
content = {}
i = 1;
for line in fp:lines() do
if i < starting_line or i >= starting_line + num_lines then
content[#content+1] = line
end
i = i + 1
end
 
if i > starting_line and i < starting_line + num_lines then
print( "Warning: Tried to remove lines after EOF." )
end
 
fp:close()
fp = io.open( filename, "w+" )
 
for i = 1, #content do
fp:write( string.format( "%s\n", content[i] ) )
end
 
fp:close()
end

[edit] OCaml

let input_line_opt ic =
try Some (input_line ic)
with End_of_file -> None
 
let delete_lines filename start skip =
if start < 1 || skip < 1 then
invalid_arg "delete_lines";
let tmp_file = filename ^ ".tmp" in
let ic = open_in filename
and oc = open_out tmp_file in
let until = start + skip - 1 in
let rec aux i =
match input_line_opt ic with
| Some line ->
if i < start || i > until
then (output_string oc line; output_char oc '\n');
aux (succ i)
| None ->
close_in ic;
close_out oc;
Sys.remove filename;
Sys.rename tmp_file filename
in
aux 1
 
let usage () =
Printf.printf "Usage:\n%s <filename> <startline> <skipnumber>\n" Sys.argv.(0);
exit 0
 
let () =
if Array.length Sys.argv < 4 then usage ();
delete_lines
Sys.argv.(1) (int_of_string Sys.argv.(2)) (int_of_string Sys.argv.(3))
$ cal > cal.txt
$ cat cal.txt
    juillet 2011    
lu ma me je ve sa di
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
 
$ ocaml deleteLines.ml cal.txt 5 2
$ cat cal.txt
    juillet 2011    
lu ma me je ve sa di
             1  2  3
 4  5  6  7  8  9 10
25 26 27 28 29 30 31
 

[edit] Perl

The value of deleting certain lines from a file notwithstanding, here's how you'd normally do it in Perl (call with perl rmlines -from=3 -to=10 filename:
#!/usr/bin/perl -n -s -i
print unless $. >= $from && $. <= $to;

If you want a backup file (maybe because deleting lines from a file in place is a pretty silly idea), change the -i in the first line to -i.bak, for example.

#!/usr/bin/perl -w
use strict ;
use Tie::File ;
 
sub deletelines {
my $arguments = shift ;
my( $file , $startfrom , $howmany ) = @{$arguments} ;
tie my @lines , 'Tie::File' , $file or die "Can't find file $file!\n" ;
my $nrecs = @lines ;
if ( $startfrom > $nrecs ) {
print "Error! Starting to delete lines past the end of the file!\n" ;
return ;
}
if ( ( $startfrom + $howmany ) > $nrecs ) {
print "Error! Trying to delete lines past the end of the file!\n" ;
return ;
}
splice @lines , $startfrom - 1 , $howmany ;
untie @lines ;
}
 
if ( @ARGV != 3 ) {
print "Error! Invoke with deletelines <filename> <start> <skiplines> !\n" ;
exit( 1 ) ;
}
 
deletelines( \@ARGV ) ;

[edit] Perl 6

sub MAIN ($filename, $beg, $len) {
my @lines = split /^^/, slurp $filename;
unlink $filename; # or rename
splice(@lines,$beg,$len) == $len or warn "Too few lines";
spurt $filename, @lines;
}
Output:
$ cal >foo
$ ./rmlines
 Usage:
   rmlines <filename> <beg> <len>
$ ./rmlines foo 1 2
$ cat foo
  1  2  3  4  5  6  7  
  8  9 10 11 12 13 14  
 15 16 17 18 19 20 21  
 22 23 24 25 26 27 28  
 29 30 31

[edit] PicoLisp

(de deleteLines (File Start Cnt)
(let L (in File (make (until (eof) (link (line)))))
(if (> (+ (dec 'Start) Cnt) (length L))
(quit "Not enough lines")
(out File
(mapc prinl (cut Start 'L))
(mapc prinl (nth L (inc Cnt))) ) ) ) )

[edit] PowerBASIC

#DIM ALL
 
FUNCTION PBMAIN () AS LONG
DIM filespec AS STRING, linein AS STRING
DIM linecount AS LONG, L0 AS LONG, ok AS LONG
 
filespec = DIR$(COMMAND$(1))
WHILE LEN(filespec)
linecount = 0: ok = 0
OPEN filespec FOR INPUT AS 1
OPEN filespec & ".tmp" FOR OUTPUT AS 2
DO UNTIL EOF(1)
LINE INPUT #1, linein
INCR linecount
IF VAL(COMMAND$(2)) <> linecount THEN
PRINT #2, linein
ELSE
ok = -1
FOR L0 = 2 TO VAL(COMMAND$(3))
IF EOF(1) THEN
ok = 1
PRINT "Tried to remove beyond the end of "; filespec
EXIT DO
END IF
LINE INPUT #1, linein
NEXT
END IF
LOOP
IF 0 = ok THEN
PRINT "Lines to remove are beyond the end of "; filespec
ELSEIF -1 = ok THEN
PRINT filespec; ": done"
END IF
CLOSE
filespec = DIR$
WEND
END FUNCTION

Sample output:

E:\users\Erik\Desktop>rmvlns.exe ?.txt 500 100
Lines to remove are beyond the end of 0.txt
Tried to remove beyond the end of 1.txt
2.txt: done
3.txt: done
4.txt: done

[edit] Python

Uses the fileinput standard module.

#!/usr/bin/env python
 
import fileinput, sys
 
fname, start, count = sys.argv[1:4]
start, count = int(start), int(count)
 
for line in fileinput.input(fname, inplace=1, backup='.orig'):
if start <= fileinput.lineno() < start + count:
pass
else:
print line[:-1]
fileinput.close()
Output:

There follows a Linux shell session showing the programs use to remove four lines starting from the second, of a file that starts with the digits one to ten on separate lines. The program keeps the original file with a ,orig prefix.

paddy@paddy-ThinkPad-T61:~$ seq 1 10 > testfile.txt
paddy@paddy-ThinkPad-T61:~$ ./remove_lines.py testfile.txt 2 4
paddy@paddy-ThinkPad-T61:~$ cat testfile.txt
1
6
7
8
9
10
paddy@paddy-ThinkPad-T61:~$ cat testfile.txt.orig
1
2
3
4
5
6
7
8
9
10
paddy@paddy-ThinkPad-T61:~$ 

[edit] Racket

 
#lang racket
(define (remove-lines file from num)
(define lines (file->lines file))
(define-values [pfx rest] (split-at lines (sub1 from)))
(display-lines-to-file (append pfx (drop rest num)) file #:exists 'replace))
 

[edit] REXX

This example is operating system dependent as this program uses the ERASE and RENAME commands.

/*REXX program to read a specified file and delete specified record(s). */
parse arg iFID ',' at ',' many /*input FID, del start, how many.*/
if iFID='' then call er "no input fileID specified."
if at='' then call er "no start number specified."
if many='' then many=1 /*Not specified? Assume 1 line.*/
stop=at+many-1 /*calculate high end of deletes. */
oFID=iFID'.out' /*the name of the output file. */
w=0
do j=1 while lines(iFID)\==0 /*J is the line number being read*/
x=linein(iFID) /*read a line from the input file*/
if j>=at & j<=stop then iterate /*if in the range, then ignore it*/
call lineout oFID,x; w=w+1 /*write line, bump the write cnt.*/
end
j=j-1
if j<stop then say "number of lines in file is less than the range given."
q='"' /*handle cases of blanks in FID. */
'ERASE' q || ifid || q
'RENAME' q || ofid || q q || ifid || q
say 'file ' iFID " had" j 'record's(j)", it now has" w 'record's(w)"."
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────ER subroutine───────────────────────*/
er: say; say '***error!***; say; say arg(1); say; exit 13
/*──────────────────────────────────S subroutine────────────────────────*/
s: if arg(1)==1 then return arg(3);return word(arg(2) '
s',1) /*plurals.*/

output when using the input of: foobar.txt,2,4

file  foobar.txt  had 10 records, it now has 6 records.

file before processing

1
 2
  3
   4
    5
     6
      7
       8
        9
         10

file after processing

1
     6
      7
       8
        9
         10

[edit] Ruby

require 'tempfile'
require 'fileutils'
require 'English'
 
def remove_lines(filename, start, num)
tmp = Tempfile.new(filename)
File.foreach(filename) do |line|
if $NR >= start and num > 0
num -= 1
else
tmp.write line
end
end
tmp.close
STDERR.puts "Warning: End of file encountered before all lines removed" if num > 0
FileUtils.copy(tmp.path, filename)
tmp.unlink
end

Test code

def setup(start, remove)
puts "remove #{remove} lines starting at line #{start}"
File.open($filename, "w") {|fh| (1..5).each {|i| fh.puts i}}
puts "before:\n" + File.read($filename)
end
 
def teardown
puts "after:\n" + File.read($filename)
puts ""
File.unlink($filename)
end
 
$filename = "test.file"
start = 2
[2, 6].each do |remove|
setup(start, remove)
remove_lines $filename, start, remove
teardown
end

output

remove 2 lines starting at line 2
before:
1
2
3
4
5
after:
1
4
5

remove 6 lines starting at line 2
before:
1
2
3
4
5
Warning: End of file encountered before all lines removed
after:
1

[edit] Run BASIC

fileName$ = "aFile.txt"
startLine = 100
lineCount = 10
 
open filename$ for input as #in
open filename$ ; "_tmp" for output as #out
 
while not(eof(#in))
lineNum = lineNum + 1
line input #in, a$
if lineNum < startLine or lineNum >= startLine + lineCount then print #out, a$
wend
close #in
close #out

[edit] Seed7

$ include "seed7_05.s7i";
include "osfiles.s7i";
 
const proc: removeLines (in string: fileName, in integer: start, in integer: count) is func
local
var file: inFile is STD_NULL;
var file: outFile is STD_NULL;
var integer: lineNumber is 1;
var string: line is "";
begin
inFile := open(fileName, "r");
outFile := open(fileName & ".tmp", "w");
while hasNext(inFile) do
line := getln(inFile);
if lineNumber < start or lineNumber >= start + count then
writeln(outFile, line);
end if;
incr(lineNumber);
end while;
close(inFile);
close(outFile);
removeFile(fileName);
moveFile(fileName & ".tmp", fileName);
end func;
 
const proc: main is func
begin
if length(argv(PROGRAM)) = 3 then
removeLines(argv(PROGRAM)[1], integer parse (argv(PROGRAM)[2]), integer parse (argv(PROGRAM)[3]));
end if;
end func;

[edit] Tcl

proc removeLines {fileName startLine count} {
# Work out range to remove
set from [expr {$startLine - 1}]
set to [expr {$startLine + $count - 2}]
# Read the lines
set f [open $fileName]
set lines [split [read $f] "\n"]
close $f
# Write the lines back out, without removed range
set f [open $fileName w]
puts -nonewline $f [join [lreplace $lines $from $to] "\n"]
close $f
}

[edit] TUSCRIPT

 
$$! input=testfile,begnr=3,endnr=4
$$ MODE TUSCRIPT
- CREATE inputfile
ERROR/STOP CREATE (input,FDF-o,-std-)
FILE/ERASE $input
LOOP n=1,9
content=CONCAT ("line",n)
DATA {content}
ENDLOOP
ENDFILE
 
- CREATE outputfile
output="outputfile"
 
ERROR/STOP CREATE (output,fdf-o,-std-)
ACCESS q: READ/RECORDS/utf8 $input L,line
ACCESS z: WRITE/RECORDS/utf8 $output L,line
PRINT "content: of output-file"
LOOP/9999
READ/NEXT/EXIT q
IF (begnr<=L&&endnr>=L) CYCLE
PRINT line
WRITE z
ENDLOOP
ENDACCESS/PRINT q
ENDACCESS/PRINT z
 

Output:

Start MAKRO   auf: XXXXXX   am: 02.12.11  um: 17:31:50
content: of output-file
line1
line2
line5
line6
line7
line8
line9
****  Eingabe: 9 Sätze von Datei -*TESTFILE
               Satzlänge: 5
****  Ausgabe: 7 Sätze auf Datei -*OUTPUTFILE
               Satzlänge: 5
Ende  MAKRO   auf: XXXXXX   am: 02.12.11  um: 17:31:50 

[edit] UNIX Shell

 
#!/bin/sh
error() {
echo "$*"
exit 1
}
 
[ $# -ne 3 ] && error "Incorrect number of parameters"
 
file=$1
start=$2
end=$3
 
[ -f $file ] || error "$file does not exist"
 
sed $start,${end}d $file >/tmp/$$ && mv /tmp/$$ $file
 

If you have GNU sed on the system, you can replace the last line with

 
sed -i $start,${end}d $file
 
Personal tools
Namespaces

Variants
Actions
Community
Explore
Misc
Toolbox