环境:OS X 10.12.4
照例先看一下man page。
- HEAD(1) BSD General Commands Manual HEAD(1)
-
- NAME
- head -- display first lines of a file
-
- SYNOPSIS
- head [-n count | -c bytes] [file ...]
-
- DESCRIPTION
- This filter displays the first count lines or bytes of each of the specified files,or of the standard input if no files are specified. If count is omitted
- it defaults to 10.
-
- If more than a single file is specified,each file is preceded by a header consisting of the string ``==> XXX <=='' where ``XXX'' is the name of the file.
-
- EXIT STATUS
- The head utility exits 0 on success,and >0 if an error occurs.
-
- SEE ALSO
- tail(1)
-
- HISTORY
- The head command appeared in PWB UNIX.
-
- BSD June 6,1993 BSD
这个程序也是比较简单的,显示文件开头的n行或者n个字符,如果没有特别指出的话,默认是10行。如果没有指明文件的话,也是从标准输入读入。如果参数中指出了多个文件,每个文件的开头会有==> XXX <==
的提示(XXX是文件名)。
实现中参数读取参考TCPL(The C Language Programming Language 5.10 Command-line Argument)。字符读入也使用了上回cat实现的xc_file.c缓存。
head.c
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
-
- #define COUNT 1
- #define BYTES 2
-
- #define XCERR_FORMAT 1
-
- void xc_open(char *aFName);
- void xc_close(void);
- int xc_getchar(void);
- void xc_readFromStdin(void);
-
- void xc_quit(int flag);
- void xc_output(int flag,int n);
-
- /* use xc_file.c to read from file */
- int main(int ac,char *av[])
- {
- int ch;
- int flag = COUNT;
- int cnt = 10; /* default 10 lines */
- int moreThanOneFile = 0;
- // int readStd = 0;
-
- /* deal with option argument */
-
- while(--ac > 0 && (*++av)[0] == '-'){
- ch = *++av[0];
- switch(ch){
- case 'n':
- flag = COUNT;
- cnt = atoi(*++av); /* av[ac] == "\0" */
- --ac; /* take one argument */
- if(cnt <= 0)
- xc_quit(XCERR_FORMAT);
- break;
- case 'c':
- flag = BYTES;
- cnt = atoi(*++av);
- --ac;
- if(cnt <= 0)
- xc_quit(XCERR_FORMAT);
- break;
- default:
- xc_quit(XCERR_FORMAT);
- }
- }
-
- if(ac == 0){
- xc_readFromStdin();
- xc_output(flag,cnt);
- }else{
- if(ac > 1)
- moreThanOneFile = 1;
- while(ac--)
- {
- xc_open(*av);
- if(moreThanOneFile)
- printf("==> %s <==\n",av[0]);
- xc_output(flag,cnt);
- if(moreThanOneFile && ac > 0)
- printf("\n");
- av++;
- }
- }
- return 0;
- }
- void xc_quit(int flag)
- {
- char str[255];
- switch(flag){
- case XCERR_FORMAT:
- strcpy(str,"Usage: head [-n count | -c bytes] [file ...]");
- break;
- }
- fprintf(stderr,"%s\n",str);
- exit(1);
- }
- void xc_output(int flag,int n)
- {
- int ch;
- int count = 0;
- while(count < n && (ch = xc_getchar()) != EOF){
- putchar(ch);
- if(flag == COUNT){
- if(ch == '\n')
- count++;
- }else if(flag == BYTES)
- count++;
- }
- xc_close();
- }
xc_file.c
- #include <stdio.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <string.h>
-
- /* BUFSIZ define in stdio.h,commonly is 1024 */
- static unsigned char chBuf[BUFSIZ];
- static int fd = -1;
- static char fName[BUFSIZ];
- static int chCur;
- static int chSum;
-
- void xc_readFromStdin(void)
- {
- /* define in unistd.h */
- fd = STDIN_FILENO;
- }
-
- void xc_open(char *aFName)
- {
- if((fd = open(aFName,O_RDONLY)) == -1){
- perror(aFName);
- exit(1);
- }
- strcpy(fName,aFName); /* record which file is opened */
- chCur = chSum = 0;
- }
-
- int xc_reload(void)
- {
- int bytes_read;
- if((bytes_read = read(fd,chBuf,BUFSIZ)) > 0){
- chCur = 0;
- chSum = bytes_read;
- return chBuf[chCur++];
- }else if(bytes_read == -1){
- perror(fName);
- exit(1);
- }else if (bytes_read == 0)
- return EOF;
- }
-
- int xc_getchar(void)
- {
- if(fd == -1)
- return EOF;
- if(chSum == chCur)
- return xc_reload();
- return chBuf[chCur++];
- }
-
- void xc_close(void)
- {
- if(fd != -1)
- {
- if(close(fd) == -1){
- perror(fName);
- exit(1);
- }
- fd = -1;
- }
- }
效果: