Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102623901
D35720.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D35720.diff
View Options
diff --git a/usr.bin/head/Makefile b/usr.bin/head/Makefile
--- a/usr.bin/head/Makefile
+++ b/usr.bin/head/Makefile
@@ -4,6 +4,7 @@
.include <src.opts.mk>
PROG= head
+LIBADD= util
HAS_TESTS=
SUBDIR.${MK_TESTS}+= tests
diff --git a/usr.bin/head/head.1 b/usr.bin/head/head.1
--- a/usr.bin/head/head.1
+++ b/usr.bin/head/head.1
@@ -28,7 +28,7 @@
.\" @(#)head.1 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
-.Dd April 10, 2018
+.Dd June 12, 2022
.Dt HEAD 1
.Os
.Sh NAME
@@ -36,6 +36,7 @@
.Nd display first lines of a file
.Sh SYNOPSIS
.Nm
+.Op Fl qv
.Op Fl n Ar count | Fl c Ar bytes
.Op Ar
.Sh DESCRIPTION
@@ -59,14 +60,30 @@
Print
.Ar count
lines of each of the specified files.
+.Pp
+Both
+.Ar count
+and
+.Ar bytes
+may also be specified with size suffixes supported by
+.Xr expand_number 3 .
+.It Fl q , Fl -quiet , Fl -silent
+Suppresses printing of headers when multiple files are being examined.
+.It Fl v , Fl -verbose
+Prepend each file with a header.
.El
.Pp
-If more than a single file is specified, each file is preceded by a
+If more than a single file is specified, or if the
+.Fl v
+option is used, each file is preceded by a
header consisting of the string
.Dq ==> XXX <==
where
.Dq XXX
is the name of the file.
+The
+.Fl q
+flag disables the printing of the header in all cases.
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
@@ -83,7 +100,8 @@
.Pp
.Dl $ head -n 500 foo | tail -n 1
.Sh SEE ALSO
-.Xr tail 1
+.Xr tail 1 ,
+.Xr expand_number 3
.Sh HISTORY
The
.Nm
diff --git a/usr.bin/head/head.c b/usr.bin/head/head.c
--- a/usr.bin/head/head.c
+++ b/usr.bin/head/head.c
@@ -57,6 +57,8 @@
#include <string.h>
#include <unistd.h>
+#include <libutil.h>
+
#include <libcasper.h>
#include <casper/cap_fileargs.h>
@@ -66,7 +68,7 @@
* Bill Joy UCB August 24, 1977
*/
-static void head(FILE *, int);
+static void head(FILE *, intmax_t);
static void head_bytes(FILE *, off_t);
static void obsolete(char *[]);
static void usage(void);
@@ -75,6 +77,9 @@
{
{"bytes", required_argument, NULL, 'c'},
{"lines", required_argument, NULL, 'n'},
+ {"quiet", no_argument, NULL, 'q'},
+ {"silent", no_argument, NULL, 'q'},
+ {"verbose", no_argument, NULL, 'v'},
{NULL, no_argument, NULL, 0}
};
@@ -82,29 +87,37 @@
main(int argc, char *argv[])
{
FILE *fp;
- char *ep;
off_t bytecnt;
- int ch, first, linecnt, eval;
+ intmax_t linecnt;
+ int ch, first, eval;
fileargs_t *fa;
cap_rights_t rights;
+ int qflag = 0;
+ int vflag = 0;
linecnt = -1;
eval = 0;
bytecnt = -1;
obsolete(argv);
- while ((ch = getopt_long(argc, argv, "+n:c:", long_opts, NULL)) != -1) {
+ while ((ch = getopt_long(argc, argv, "+n:c:qv", long_opts, NULL)) != -1) {
switch(ch) {
case 'c':
- bytecnt = strtoimax(optarg, &ep, 10);
- if (*ep || bytecnt <= 0)
+ if (expand_number(optarg, &bytecnt) || bytecnt <= 0)
errx(1, "illegal byte count -- %s", optarg);
break;
case 'n':
- linecnt = strtol(optarg, &ep, 10);
- if (*ep || linecnt <= 0)
+ if (expand_number(optarg, &linecnt) || linecnt <= 0)
errx(1, "illegal line count -- %s", optarg);
break;
+ case 'q':
+ qflag = 1;
+ vflag = 0;
+ break;
+ case 'v':
+ qflag = 0;
+ vflag = 1;
+ break;
case '?':
default:
usage();
@@ -134,7 +147,7 @@
eval = 1;
continue;
}
- if (argc > 1) {
+ if (vflag || (qflag == 0 && argc > 1)) {
(void)printf("%s==> %s <==\n",
first ? "" : "\n", *argv);
first = 0;
@@ -155,7 +168,7 @@
}
static void
-head(FILE *fp, int cnt)
+head(FILE *fp, intmax_t cnt)
{
char *cp;
size_t error, readlen;
diff --git a/usr.bin/head/tests/head_test.sh b/usr.bin/head/tests/head_test.sh
--- a/usr.bin/head/tests/head_test.sh
+++ b/usr.bin/head/tests/head_test.sh
@@ -119,6 +119,48 @@
atf_check cmp outfile expectfile
}
+atf_test_case silent_header
+silent_header_head() {
+ atf_set "descr" "Test head(1)'s silent header feature"
+}
+silent_header_body() {
+ #head(1) defaults to head -n 10 if no args are given.
+ jot 11 1 11 > file1
+ jot 11 2 12 > file2
+ jot 10 1 10 > expectfile
+ jot 10 2 11 >> expectfile
+ head -q file1 file2 > outfile
+ atf_check cmp outfile expectfile
+}
+
+atf_test_case verbose_header
+verbose_header_head() {
+ atf_set "descr" "Test head(1)'s verbose header feature"
+}
+verbose_header_body() {
+ #head(1) defaults to head -n 10 if no args are given.
+ jot -b test 10 > file1
+ echo '==> file1 <==' > expectfile
+ cat file1 >> expectfile
+ head -v file1 > outfile
+ atf_check cmp outfile expectfile
+}
+
+atf_test_case si_number
+si_number_head() {
+ atf_set "descr" "Test head(1)'s SI number feature"
+}
+si_number_body() {
+ jot -b aaaaaaa 129 > file1
+ jot -b aaaaaaa 128 > expectfile
+ head -c 1k file1 > outfile
+ atf_check cmp outfile expectfile
+ jot 1025 1 1025 > file1
+ jot 1024 1 1024 > expectfile
+ head -n 1k file1 > outfile
+ atf_check cmp outfile expectfile
+}
+
atf_init_test_cases() {
atf_add_test_case empty_file
atf_add_test_case default_no_options
@@ -129,4 +171,7 @@
atf_add_test_case missing_line_count
atf_add_test_case invalid_line_count
atf_add_test_case read_from_stdin
+ atf_add_test_case silent_header
+ atf_add_test_case verbose_header
+ atf_add_test_case si_number
}
diff --git a/usr.bin/tail/Makefile b/usr.bin/tail/Makefile
--- a/usr.bin/tail/Makefile
+++ b/usr.bin/tail/Makefile
@@ -5,6 +5,7 @@
PROG= tail
SRCS= forward.c misc.c read.c reverse.c tail.c
+LIBADD= util
.if ${MK_CASPER} != "no" && !defined(RESCUE)
LIBADD+= casper
diff --git a/usr.bin/tail/extern.h b/usr.bin/tail/extern.h
--- a/usr.bin/tail/extern.h
+++ b/usr.bin/tail/extern.h
@@ -77,5 +77,5 @@
int maparound(struct mapinfo *, off_t);
void printfn(const char *, int);
-extern int Fflag, fflag, qflag, rflag, rval, no_files;
+extern int Fflag, fflag, qflag, rflag, rval, no_files, vflag;
extern fileargs_t *fa;
diff --git a/usr.bin/tail/forward.c b/usr.bin/tail/forward.c
--- a/usr.bin/tail/forward.c
+++ b/usr.bin/tail/forward.c
@@ -246,8 +246,8 @@
int ch;
while ((ch = getc(file->fp)) != EOF) {
- if (last != file && no_files > 1) {
- if (!qflag)
+ if (last != file) {
+ if (vflag || (qflag == 0 && no_files > 1))
printfn(file->file_name, 1);
last = file;
}
@@ -325,7 +325,7 @@
if (file->fp) {
active = 1;
n++;
- if (no_files > 1 && !qflag)
+ if (vflag || (qflag == 0 && no_files > 1))
printfn(file->file_name, 1);
forward(file->fp, file->file_name, style, off, &file->st);
if (Fflag && fileno(file->fp) != STDIN_FILENO)
diff --git a/usr.bin/tail/tail.1 b/usr.bin/tail/tail.1
--- a/usr.bin/tail/tail.1
+++ b/usr.bin/tail/tail.1
@@ -31,7 +31,7 @@
.\" @(#)tail.1 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
-.Dd March 22, 2020
+.Dd July 12, 2022
.Dt TAIL 1
.Os
.Sh NAME
@@ -40,7 +40,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl F | f | r
-.Op Fl q
+.Op Fl qv
.Oo
.Fl b Ar number | Fl c Ar number | Fl n Ar number
.Oc
@@ -116,7 +116,7 @@
The location is
.Ar number
lines.
-.It Fl q
+.It Fl q, Fl -quiet, Fl -silent
Suppresses printing of headers when multiple files are being examined.
.It Fl r
The
@@ -135,16 +135,26 @@
The default for the
.Fl r
option is to display all of the input.
+.It Fl v, Fl -verbose
+Prepend each file with a header.
.El
.Pp
-If more than a single file is specified, each file is preceded by a
+If more than a single file is specified, or if the
+.Fl v
+option is used, each file is preceded by a
header consisting of the string
.Dq Li "==> " Ns Ar XXX Ns Li " <=="
where
.Ar XXX
-is the name of the file unless
+is the name of the file.
+The
.Fl q
-flag is specified.
+flag disables the printing of the header in all cases.
+.Pp
+All
+.Ar number
+arguments may also be specified with size suffixes supported by
+.Xr expand_number 3 .
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
@@ -161,7 +171,8 @@
.Sh SEE ALSO
.Xr cat 1 ,
.Xr head 1 ,
-.Xr sed 1
+.Xr sed 1 ,
+.Xr expand_number 3
.Sh STANDARDS
The
.Nm
diff --git a/usr.bin/tail/tail.c b/usr.bin/tail/tail.c
--- a/usr.bin/tail/tail.c
+++ b/usr.bin/tail/tail.c
@@ -59,12 +59,14 @@
#include <string.h>
#include <unistd.h>
+#include <libutil.h>
+
#include <libcasper.h>
#include <casper/cap_fileargs.h>
#include "extern.h"
-int Fflag, fflag, qflag, rflag, rval, no_files;
+int Fflag, fflag, qflag, rflag, rval, no_files, vflag;
fileargs_t *fa;
static void obsolete(char **);
@@ -75,6 +77,9 @@
{"blocks", required_argument, NULL, 'b'},
{"bytes", required_argument, NULL, 'c'},
{"lines", required_argument, NULL, 'n'},
+ {"quiet", no_argument, NULL, 'q'},
+ {"silent", no_argument, NULL, 'q'},
+ {"verbose", no_argument, NULL, 'v'},
{NULL, no_argument, NULL, 0}
};
@@ -88,7 +93,6 @@
enum STYLE style;
int ch, first;
file_info_t file, *filep, *files;
- char *p;
cap_rights_t rights;
/*
@@ -106,8 +110,9 @@
#define ARG(units, forward, backward) { \
if (style) \
usage(); \
- off = strtoll(optarg, &p, 10) * (units); \
- if (*p) \
+ if (expand_number(optarg, &off)) \
+ err(1, "illegal offset -- %s", optarg); \
+ if (off > INT64_MAX / units || off < INT64_MIN / units ) \
errx(1, "illegal offset -- %s", optarg); \
switch(optarg[0]) { \
case '+': \
@@ -127,7 +132,7 @@
obsolete(argv);
style = NOTSET;
off = 0;
- while ((ch = getopt_long(argc, argv, "+Fb:c:fn:qr", long_opts, NULL)) !=
+ while ((ch = getopt_long(argc, argv, "+Fb:c:fn:qrv", long_opts, NULL)) !=
-1)
switch(ch) {
case 'F': /* -F is superset of (and implies) -f */
@@ -147,10 +152,15 @@
break;
case 'q':
qflag = 1;
+ vflag = 0;
break;
case 'r':
rflag = 1;
break;
+ case 'v':
+ vflag = 1;
+ qflag = 0;
+ break;
case '?':
default:
usage();
@@ -230,7 +240,7 @@
ierr(fn);
continue;
}
- if (argc > 1 && !qflag) {
+ if (vflag || (qflag == 0 && argc > 1)) {
printfn(fn, !first);
first = 0;
}
diff --git a/usr.bin/tail/tests/tail_test.sh b/usr.bin/tail/tests/tail_test.sh
--- a/usr.bin/tail/tests/tail_test.sh
+++ b/usr.bin/tail/tests/tail_test.sh
@@ -352,6 +352,47 @@
atf_check kill $pid
}
+atf_test_case silent_header
+silent_header_head() {
+ atf_set "descr" "Test tail(1)'s silent header feature"
+}
+silent_header_body() {
+ jot 11 1 11 > file1
+ jot 11 2 12 > file2
+ jot 10 2 11 > expectfile
+ jot 10 3 12 >> expectfile
+ tail -q file1 file2 > outfile
+ atf_check cmp outfile expectfile
+}
+
+atf_test_case verbose_header
+verbose_header_head() {
+ atf_set "descr" "Test tail(1)'s verbose header feature"
+}
+verbose_header_body() {
+ jot 11 1 11 > file1
+ echo '==> file1 <==' > expectfile
+ jot 10 2 11 >> expectfile
+ tail -v file1 > outfile
+ atf_check cmp outfile expectfile
+}
+
+atf_test_case si_number
+si_number_head() {
+ atf_set "descr" "Test tail(1)'s SI number feature"
+}
+si_number_body() {
+ jot -b aaaaaaa 129 > file1
+ jot -b aaaaaaa 128 > expectfile
+ tail -c 1k file1 > outfile
+ atf_check cmp outfile expectfile
+ jot 1025 1 1025 > file1
+ jot 1024 2 1025 > expectfile
+ tail -n 1k file1 > outfile
+ atf_check cmp outfile expectfile
+}
+
+
atf_init_test_cases()
{
atf_add_test_case empty_r
@@ -372,4 +413,7 @@
atf_add_test_case follow
atf_add_test_case follow_stdin
atf_add_test_case follow_rename
+ atf_add_test_case silent_header
+ atf_add_test_case verbose_header
+ atf_add_test_case si_number
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Nov 15, 11:30 PM (2 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14649473
Default Alt Text
D35720.diff (11 KB)
Attached To
Mode
D35720: Improve usability of head(1) and tail(1):
Attached
Detach File
Event Timeline
Log In to Comment