morrell@hpsal2.HP.COM (Michael Morrell) (04/08/88)
> Does anyone know of a utility which will extract the nth line of a > file? I can easily write one but then I thought a general case > utility might exist. The utility could have the following > description: > > extract line-no [files] > > Extract a specified line number, range of lines, or > series of lines from stdin or a series of files. > > > Thanks in advance, > Jeremy Uejio (pronounced 'oo-ay-joe') > uejio@lll-lcc.llnl.gov ---------- Try using "sed". sed -n a,bp file will extract lines a thru b from "file". To get a series of lines, use sed -n '1,3p;10,21p;33,40p' file or sed -n -e 1,3p -e 10,21p -e 33,40p file Michael Morrell
decot@hpisod2.HP.COM (Dave Decot) (04/09/88)
# This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by decot at hpisod2 on Fri Apr 8 16:54:06 1988 # # This archive contains: # lines.1 lines.c # LANG=""; export LANG echo x - lines.1 cat >lines.1 <<'@EOF' .TH LINES 1 .SH NAME lines \- print selected line ranges from files .SH SYNOPSIS \fBlines\fR \fIrange\fR ... [ \fIfilename\fR ... ] .SH DESCRIPTION .I Lines is a filter which prints selected lines from its input. Each \fIrange\fR argument specifies a group of contiguous lines to be printed. If one or more \fIfilename\fRs are supplied, the same lines are selected from each named file instead of the standard input. In this case, each file is processed completely before moving on to the next file. .PP Each printed line is preceded by its line number, a colon, and a tab. If more than one \fIfilename\fR was specified, each line will be preceded by the name of the file from which it came, unless the name is more than 6 characters long. In this case, the name of each file is printed once before the lines from that file are printed. .PP Each \fIrange\fR should be one of the following, where \fIn\fR, \fIm\fR, and \fIk\fR are positive integers: .TP \fIn\fR Print line \fIn\fR. .TP \fIm\fB\-\fIn\fR Print lines \fIm\fR through \fIn\fR, inclusive. If \fIm\fR is omitted, the range selected begins at the line after the end of the previous range, or at line 1 if there is no previous range. If \fIn\fR is omitted, the range ends at the end of the file. .TP \fIm\fB+\fIk\fR Print lines \fIm\fR through \fIm\fB+\fIk\fR, inclusive. If \fIm\fR is omitted, the range selected begins at the line after the end of the previous range, or at line 1 if there is no previous range. If \fIk\fR is omitted, the range ends at the end of the file. .PP If .I lines is reading from a pipe, instead of from a file, sequential \fIrange\fRs must not specify lines in any but their numerical order. .SH AUTHOR Dave Decot, Hewlett-Packard Company, {hplabs,ucbvax}!hpda!decot. .SH "SEE ALSO" cat(1), comm(1), cut(1), head(1), nl(1), paste(1), pr(1), rev(1) .SH "BUGS" Lines longer than BUFSIZ are considered to be broken into pieces of that size or smaller. @EOF chmod 664 lines.1 echo x - lines.c cat >lines.c <<'@EOF' /*------------------------------------------------------------------------*\ * lines.c - Version 0.0 Copyright (c) 1986, 1987, 1988 by Dave Decot * * All rights reserved. * * * * FREEWARE: you may use this for anything as long as you don't charge * * someone else extra for using or having it. * * * * This notice must be present in all copies you distribute. * \*------------------------------------------------------------------------*/ #include <stdio.h> #include <ctype.h> extern void exit(), perror(); #define MAXRANGES 200 long start[MAXRANGES]; long stop[MAXRANGES]; int rangecount = 0; long laststop = 0; char *prog, *filename = "standard input"; int filecount; main(argc, argv) int argc; char *argv[]; { int i, plus, badrange = 0; char *p; prog = argv[0]; argv++, argc--; for (rangecount = 0; rangecount < argc; rangecount++) { plus = 0; p = argv[rangecount]; while (isdigit(*p)) start[rangecount] = start[rangecount] * 10 + *p++ - '0'; if (p == argv[rangecount] && (*p == '+' || *p == '-')) if (laststop == EOF) badrange++; else start[rangecount] = laststop+1; if (*p == '-' || *p == '+') { if (*p == '+') plus++; if (*++p == '\0' || *p == ',') laststop = stop[rangecount] = EOF; } else if (*p == '\0' || *p == ',') laststop = stop[rangecount] = start[rangecount]; if (stop[rangecount] == 0) { while (isdigit(*p)) stop[rangecount] = stop[rangecount] * 10 + *p++ - '0'; if (*p != '\0' && *p != ',') break; if (plus) stop[rangecount] += start[rangecount]; laststop = stop[rangecount]; if (laststop < start[rangecount]) { fprintf(stderr, "%s: range %d-%d goes backward\n", prog, start[rangecount], laststop); exit(2); } } if (*p != ',' && *p != '\0') break; if (start[rangecount] == 0 || stop[rangecount] == 0) { fprintf(stderr, "%s: 0 is not a line number\n", prog); exit(1); } if (badrange) { fprintf(stderr, "%s: can't use two adjacent + or - signs\n", prog); exit(1); } if (*p == ',') { (argv--)[rangecount] = p + 1; argc++; continue; } } filecount = argc - rangecount; if (argc - rangecount == 0) process(stdin); for (i = rangecount; i < argc; i++) process(fopen(filename = argv[i], "r")); return 0; } process(fp) FILE *fp; { long line = 0; int range; char buf[BUFSIZ]; extern int errno; if (rangecount == 0) { fprintf(stderr, "Usage: %s range ... [file ...]\n", prog); fprintf(stderr, "\twhere range is one of:\n"); fprintf(stderr, "\t m\tline m\n"); fprintf(stderr, "\t m-n\tline m thru line n\n"); fprintf(stderr, "\t m- m+\tline m to end of file\n"); fprintf(stderr, "\t -n\tthru line n\n"); fprintf(stderr, "\t - +\tthru end of file\n"); fprintf(stderr, "\t m+k\tline m thru line m+k\n"); exit(-1); } if (fp == NULL) { perror(filename); return; } if (filecount > 1 && strlen(filename) > 6) printf("%s:\n", filename); for (range = 0; range < rangecount; range++) { if (line > start[range]) { line = errno = 0; rewind(fp); if (errno != 0) { fprintf(stderr, "%s: can't rewind %s\n", prog, filename); return; } } while (line < start[range] && fgets(buf, BUFSIZ, fp) != NULL) line++; if (line < start[range]) { fprintf(stderr, "%s: only %ld lines in %s\n", prog, line, filename); return; } while (stop[range] == EOF || line <= stop[range]) { if (filecount > 1 && strlen(filename) <= 6) printf("%s:\t", filename); printf("%ld:\t", line); fputs(buf, stdout); if (line == stop[range] || fgets(buf, BUFSIZ, fp) == NULL) break; line++; } if (stop[range] != EOF && line < stop[range]) { fprintf(stderr, "%s: only %ld lines in %s\n", prog, line, filename); return; } } } @EOF chmod 664 lines.c exit 0