0%

Linux 之 wc 查看文件信息

wc命令可以查看一下文件的行数、字数、字符数的信息。

官方定义为:

wc - print newline, word, and byte counts for each file

语法

1
$ wc [-clw][--help][--version][文件...]

参数

  • -c--bytes--chars 只显示Bytes数。
  • -l--lines 显示行数。
  • -w--words 只显示字数。
  • -L--max-line-length 打印最长一行的长度

简单的使用 wc统计

在默认的情况下,wc将计算指定文件的行数、字数,以及字节数。使用的命令为:

1
$ wc file1 

先查看file1文件的内容,可以看到:

1
2
$ cat file1  
Hello World!
1
2
$  wc file1 	# file1文件的统计信息
1 2 13 file1 # file1文件的行数为1、单词数2、字节数13

其中,3 个数字分别表示file1文件的行数单词数,以及该文件的字节数

同时统计多个文件

如果想同时统计多个文件的信息,例如同时统计file1file2file3,可使用如下命令:

1
2
3
4
5
$ wc file*
1 2 13 file1
2 5 33 file2
4 16 76 file3
7 23 122 total # 总计输出信息

统计最长一行的长度

这个对于终端输出比较有用,要知道以前的终端最长支持80个字符。

其实当前倒是没有这个限制,不过稍短一些的代码看着还是赏心悦目的。

比如查看系统的版本:

1
2
$ wc -L /etc/redhat-release 
40 /etc/redhat-release

可知这一行的最长为40个字符。

而此时我们就可以使用这个技巧来获取一个工程所有文件最长的是多少。

你是干什么的 whatis

其实整个命令已出现,你的脑海里面应该浮现的是:

What is your name?

如题所述,这个命令用于查询一个命令到底执行了什么功能,并将查询的结果输出出来,相当于man的一个选项-f

whatis的官方定义为:

whatis - display manual page descriptions

仅仅提供一个比较简单的命令描述.

使用方法也比较简单,如下:

1
$ whatis [options] name

其中的name可以是Linux命令、系统调用、库函数、系统等等内容

以前面的命令为例,执行如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ whatis ls cd file cat more less
ls (1) - list directory contents
ls (1p) - list directory contents
cd (1) - bash built-in commands, see bash(1)
cd (1p) - change the working directory
cd (n) - Change working directory
file (1) - determine file type
file (1p) - determine file type
file (n) - Manipulate file names and attributes
cat (1) - concatenate files and print on the standard output
cat (1p) - concatenate and print files
more (1) - file perusal filter for crt viewing
more (1p) - display files on a page-by-page basis
less (1) - opposite of more
less (3pm) - perl pragma to request less of something

可以看到whatis是支持同时查询多个命令的

拓展

whatis可以通过-w-r以及-C等选项来设定通配符、正则表达式以及配置文件等等,不过最简单的还是简单查看一个命令的简单描述,其他的可以交给man来处理。

whatis 你是干什么的

其实整个命令已出现,你的脑海里面应该浮现的是:

What is your name?

如题所述,这个命令用于查询一个命令到底执行了什么功能,并将查询的结果输出出来,相当于man的一个选项-f

whatis的官方定义为:

whatis - display manual page descriptions

仅仅提供一个比较简单的命令描述.

使用方法也比较简单,如下:

1
$ whatis [options] name

其中的name可以是Linux命令、系统调用、库函数、系统等等内容

以前面的命令为例,执行如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ whatis ls cd file cat more less
ls (1) - list directory contents
ls (1p) - list directory contents
cd (1) - bash built-in commands, see bash(1)
cd (1p) - change the working directory
cd (n) - Change working directory
file (1) - determine file type
file (1p) - determine file type
file (n) - Manipulate file names and attributes
cat (1) - concatenate files and print on the standard output
cat (1p) - concatenate and print files
more (1) - file perusal filter for crt viewing
more (1p) - display files on a page-by-page basis
less (1) - opposite of more
less (3pm) - perl pragma to request less of something

可以看到whatis是支持同时查询多个命令的

拓展

whatis可以通过-w-r以及-C等选项来设定通配符、正则表达式以及配置文件等等,不过最简单的还是简单查看一个命令的简单描述,其他的可以交给man来处理。

聊聊main函数

main字面的意思就是主要的意思,在程序里面也是,并且更重要了,是主函数,何为主函数,就是程序运行会执行的第一个程序,意即程序的入口,如果说眼睛是心灵的窗户,那么main就是程序的大门。

在C99标准之前,main函数可以没有返回类型或者使用void,如下所示:

1
2
3
4
5
/*beginner/main/main1.c*/

main()
{
}

或者

1
2
3
4
5
6
/*beginner/main/main2.c*/

void main()
{
}

这两个可以称为最短小精悍的程序了,不会出错,因为没有语句。

如果使用C99标准编译,就可以看到如下的警告信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
main1.c:3:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
main()
^
1 warning generated.
gcc -o main2 main2.c
main2.c:3:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]
void main()
^
main2.c:3:1: note: change return type to 'int'
void main()
^~~~
int
1 warning generated.

警告的含义就是我们的mian函数是有血有肉的,是有正儿八经的返回值的,这个返回值的类型就是int,所以这个程序:

1
2
3
4
5
/*beginner/main/main3.c*/

int main()
{
}

OK,完美编译,没有任何报错信息,不过终归看着少了点什么,是的,如果定义了返回类型,就需要有相应的返回,所以第一个标准的简单C语言函数如下所示:

1
2
3
4
5
6
/*beginner/main/main4.c*/

int main()
{
return 0;
}

main函数的形式

恩,既然写出了main函数的标准形式,这里就需要讨论一个问题,为什么有时候看到int main(),有时候又看到int main(int argc, char *argv[])呢,具体的形式如下所示:

无参数的main函数

1
2
3
4
5
6
7
8
/*beginner/main/main5.c*/

int main()
{
printf("Hello World\n");
return 0;
}

可以看到上面这个例子,只是打印了hello world,并没有其他语句。

而下面的例子,我们看到使用到了argc和argv,所谓的形参,所以在有需要的时候才会出现这种形式,就好像是黄蓉给郭靖的几个锦囊^_^。

有参数的main函数

1
2
3
4
5
6
7
8
9
10
11
12
/*beginner/main/main6.c*/

int main(int argc, char *argv[])
{
printf("The are %d arguments.\n", argc);
int i;
for (i = 0; i < argc; i++)
printf("%s ", argv[i]);
printf("\n");
return 0;
}

编译运行

直接输入make就可以了。

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
#beginner/main/Makefile
ALL : main1 main2 main3 main4 main5 main6

main1: main1.c
gcc -o main1 main1.c

main2: main2.c
gcc -o main2 main2.c

main3: main3.c
gcc -o main3 main3.c

main4: main4.c
gcc -o main4 main4.c

main5: main5.c
gcc -o main5 main5.c

main6: main6.c
gcc -o main6 main6.c

.PHONY : clean

clean:
rm -f main1 main2 main3 main4 main5 main6

MALLOC(3) Linux Programmer’s Manual MALLOC(3)

NAME
malloc, free, calloc, realloc - allocate and free dynamic memory

SYNOPSIS
#include <stdlib.h>

   void *malloc(size_t size);
   void free(void *ptr);
   void *calloc(size_t nmemb, size_t size);
   void *realloc(void *ptr, size_t size);
   void *reallocarray(void *ptr, size_t nmemb, size_t size);

Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

   reallocarray():
       Since glibc 2.29:
           _DEFAULT_SOURCE
       Glibc 2.28 and earlier:
           _GNU_SOURCE

DESCRIPTION
The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not initialized. If size is 0, then malloc() returns either NULL, or a unique
pointer value that can later be successfully passed to free().

   The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc(), or realloc().  Otherwise, or if free(ptr) has al‐
   ready been called before, undefined behavior occurs.  If ptr is NULL, no operation is performed.

   The  calloc()  function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to the allocated memory.  The memory is set to zero.  If nmemb or size
   is 0, then calloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().  If the multiplication of nmemb and size would  result  in  integer
   overflow, then calloc() returns an error.  By contrast, an integer overflow would not be detected in the following call to malloc(), with the result that an incorrectly sized block of
   memory would be allocated:

       malloc(nmemb * size);

   The realloc() function changes the size of the memory block pointed to by ptr to size bytes.  The contents will be unchanged in the range from the start of the region up to the  mini‐
   mum of the old and new sizes.  If the new size is larger than the old size, the added memory will not be initialized.  If ptr is NULL, then the call is equivalent to malloc(size), for
   all values of size; if size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr).  Unless ptr is NULL, it must have been returned by an earlier call to mal‐
   loc(), calloc(), or realloc().  If the area pointed to was moved, a free(ptr) is done.

   The reallocarray() function changes the size of the memory block pointed to by ptr to be large enough for an array of nmemb elements, each of which is size bytes.  It is equivalent to
   the call

           realloc(ptr, nmemb * size);

   However, unlike that realloc() call, reallocarray() fails safely in the case where the multiplication would overflow.  If such an overflow occurs, reallocarray()  returns  NULL,  sets
   errno to ENOMEM, and leaves the original block of memory unchanged.

RETURN VALUE
The malloc() and calloc() functions return a pointer to the allocated memory, which is suitably aligned for any built-in type. On error, these functions return NULL. NULL may also
be returned by a successful call to malloc() with a size of zero, or by a successful call to calloc() with nmemb or size equal to zero.

   The free() function returns no value.

   The realloc() function returns a pointer to the newly allocated memory, which is suitably aligned for any built-in type, or NULL if the request failed.  The returned  pointer  may  be
   the  same as ptr if the allocation was not moved (e.g., there was room to expand the allocation in-place), or different from ptr if the allocation was moved to a new address.  If size
   was equal to 0, either NULL or a pointer suitable to be passed to free() is returned.  If realloc() fails, the original block is left untouched; it is not freed or moved.

   On success, the reallocarray() function returns a pointer to the newly allocated memory.  On failure, it returns NULL and the original block of memory is left untouched.

ERRORS
calloc(), malloc(), realloc(), and reallocarray() can fail with the following error:

   ENOMEM Out of memory.  Possibly, the application hit the RLIMIT_AS or RLIMIT_DATA limit described in getrlimit(2).

ATTRIBUTES
For an explanation of the terms used in this section, see attributes(7).

   ┌─────────────────────┬───────────────┬─────────┐
   │Interface            │ Attribute     │ Value   │
   ├─────────────────────┼───────────────┼─────────┤
   │malloc(), free(),    │ Thread safety │ MT-Safe │
   │calloc(), realloc()  │               │         │
   └─────────────────────┴───────────────┴─────────┘

CONFORMING TO
malloc(), free(), calloc(), realloc(): POSIX.1-2001, POSIX.1-2008, C89, C99.

   reallocarray() is a nonstandard extension that first appeared in OpenBSD 5.6 and FreeBSD 11.0.

NOTES
By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. In case
it turns out that the system is out of memory, one or more processes will be killed by the OOM killer. For more information, see the description of /proc/sys/vm/overcommit_memory and
/proc/sys/vm/oom_adj in proc(5), and the Linux kernel source file Documentation/vm/overcommit-accounting.rst.

   Normally, malloc() allocates memory from the heap, and adjusts the size of the heap as required, using sbrk(2).  When allocating blocks of memory larger than MMAP_THRESHOLD bytes, the
   glibc  malloc()  implementation  allocates the memory as a private anonymous mapping using mmap(2).  MMAP_THRESHOLD is 128 kB by default, but is adjustable using mallopt(3).  Prior to
   Linux 4.7 allocations performed using mmap(2) were unaffected by the RLIMIT_DATA resource limit; since Linux 4.7, this limit is also enforced for allocations performed using mmap(2).

   To avoid corruption in multithreaded applications, mutexes are used internally to protect the memory-management data structures employed by these functions.  In a multithreaded appli‐
   cation  in  which  threads  simultaneously  allocate and free memory, there could be contention for these mutexes.  To scalably handle memory allocation in multithreaded applications,
   glibc creates additional memory allocation arenas if mutex contention is detected.  Each arena is a large region of memory that is internally allocated by the system (using brk(2)  or
   mmap(2)), and managed with its own mutexes.

   SUSv2 requires malloc(), calloc(), and realloc() to set errno to ENOMEM upon failure.  Glibc assumes that this is done (and the glibc versions of these routines do this); if you use a
   private malloc implementation that does not set errno, then certain library routines may fail without having a reason in errno.

   Crashes in malloc(), calloc(), realloc(), or free() are almost always related to heap corruption, such as overflowing an allocated chunk or freeing the same pointer twice.

   The malloc() implementation is tunable via environment variables; see mallopt(3) for details.

SEE ALSO
valgrind(1), brk(2), mmap(2), alloca(3), malloc_get_state(3), malloc_info(3), malloc_trim(3), malloc_usable_size(3), mallopt(3), mcheck(3), mtrace(3), posix_memalign(3)

   For details of the GNU C library implementation, see ⟨https://sourceware.org/glibc/wiki/MallocInternals⟩.

COLOPHON
This page is part of release 5.05 of the Linux man-pages project. A description of the project, information about reporting bugs, and the latest version of this page, can be found at
https://www.kernel.org/doc/man-pages/.

GNU 2020-02-09 MALLOC(3)

聊聊main函数

main字面的意思就是主要的意思,在程序里面也是,并且更重要了,是主函数,何为主函数,就是程序运行会执行的第一个程序,意即程序的入口,如果说眼睛是心灵的窗户,那么main就是程序的大门。

在C99标准之前,main函数可以没有返回类型或者使用void,如下所示:

1
2
3
4
5
/*beginner/main/main1.c*/

main()
{
}

或者

1
2
3
4
5
6
/*beginner/main/main2.c*/

void main()
{
}

这两个可以称为最短小精悍的程序了,不会出错,因为没有语句。

如果使用C99标准编译,就可以看到如下的警告信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
main1.c:3:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
main()
^
1 warning generated.
gcc -o main2 main2.c
main2.c:3:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]
void main()
^
main2.c:3:1: note: change return type to 'int'
void main()
^~~~
int
1 warning generated.

警告的含义就是我们的mian函数是有血有肉的,是有正儿八经的返回值的,这个返回值的类型就是int,所以这个程序:

1
2
3
4
5
/*beginner/main/main3.c*/

int main()
{
}

OK,完美编译,没有任何报错信息,不过终归看着少了点什么,是的,如果定义了返回类型,就需要有相应的返回,所以第一个标准的简单C语言函数如下所示:

1
2
3
4
5
6
/*beginner/main/main4.c*/

int main()
{
return 0;
}

main函数的形式

恩,既然写出了main函数的标准形式,这里就需要讨论一个问题,为什么有时候看到int main(),有时候又看到int main(int argc, char *argv[])呢,具体的形式如下所示:

无参数的main函数

1
2
3
4
5
6
7
8
/*beginner/main/main5.c*/

int main()
{
printf("Hello World\n");
return 0;
}

可以看到上面这个例子,只是打印了hello world,并没有其他语句。

而下面的例子,我们看到使用到了argc和argv,所谓的形参,所以在有需要的时候才会出现这种形式,就好像是黄蓉给郭靖的几个锦囊^_^。

有参数的main函数

1
2
3
4
5
6
7
8
9
10
11
12
/*beginner/main/main6.c*/

int main(int argc, char *argv[])
{
printf("The are %d arguments.\n", argc);
int i;
for (i = 0; i < argc; i++)
printf("%s ", argv[i]);
printf("\n");
return 0;
}

编译运行

直接输入make就可以了。

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
#beginner/main/Makefile
ALL : main1 main2 main3 main4 main5 main6

main1: main1.c
gcc -o main1 main1.c

main2: main2.c
gcc -o main2 main2.c

main3: main3.c
gcc -o main3 main3.c

main4: main4.c
gcc -o main4 main4.c

main5: main5.c
gcc -o main5 main5.c

main6: main6.c
gcc -o main6 main6.c

.PHONY : clean

clean:
rm -f main1 main2 main3 main4 main5 main6


一旦当我懂得了珍惜的时候 本该珍惜的东西早已悄悄地从这个世界溜走了 - 季羡林 《赋得永久的悔》


能够百分之六十为他人着想 百分之四十为自己着想 他就是一个及格的好人 - 季羡林 《季羡林读书与做人》


逢人不说人间事 便是人间无事人 - 杜荀鹤《赠质上人》


黑夜给了我黑色的眼睛 我却用它来寻找光明 - 顾城《一代人》



我曾经跨过山和大海 也穿过人山人海 我曾经拥有着的一切 转眼都飘散如烟 - 朴树《平凡之路》



不是成功的路太远
而是能坚持的人不多


这个世界上总会有人陪你走一段
只要你坚持下去


当你对这个世界敞开怀抱的时候

这个世界才会对你敞开怀抱

当你拒绝这个世界

你也必然会被这个世界所拒绝。


最可怕的敌人

就是没有坚强的信念

  • 罗曼·罗兰

意志坚强的人

能把世界放在手中

像泥块一样任意揉捏

  • 歌德

C语言 argc和argv

argcargv是最熟悉的陌生人。

为什么说他们熟悉,是因为如果你用的IDE比较多,大部分的main函数的样子是这样子的int main(int argc, char *argv[])

说它们陌生是因为,你可能写了半年的程序也没有实际用过这两个参数,不明所以。

好的,先来说说它们的叫法,或许也不对:

  • argc:argument counter,读作arg - C,是一个整型
  • argv:argument vector,读作 arg-V,是一个二维字符数组

具体什么意思呢,还记不记得前面说的scanf,可以采集键盘输入,恩,运行程序,然后等待我们输入,这两个参数的含义是在运行程序的时候就直接输入,比如,有两个程序bigger和smaller,我想后面直接跟两个参数来输入较大值 或者较小值,用法如下:

1
2
$ ./bigger 5 4
$ ./smaller 15 23

这个时候就需要argc和argv了。

比如下面这个例子:

1
2
3
4
5
6
7
8
9
10
/*beginner/argcargv/argcargv1.c*/

#include <stdio.h>

int main(int argc, char *argv[])
{
printf("argc = %d\n", argc);
return 0;
}

编译运行:

1
2
3
4
5
6
7
8
9
10
11
12
$ ./argcargv1 
argc = 1
$ ./argcargv1 1
argc = 2
$ ./argcargv1 1 2
argc = 3
$ ./argcargv1 1 2 3
argc = 4
$ ./argcargv1 1 2 3 4
argc = 5
$ ./argcargv1 1 2 3 4 1234
argc = 6

哇,amazingargc的值根据你的输入参数在自动修改,这就是argc的意思,就是命令行的个数统计。

下面看看argv的用法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
/*beginner/argcargv/argcargv2.c*/

#include <stdio.h>

int main(int argc, char *argv[])
{
printf("argv are :\n");
int i;
for (i = 0; i < argc; i++)
printf("argv[%d] = %s\n", i, argv[i]);
return 0;
}

这里有个需要留意的地方,就是我们在使用argv的时候需要配合argc,因为这就涉及到数组溢出的issue了。

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ ./argcargv2 1
argv are :
argv[0] = ./argcargv2
argv[1] = 1
$ ./argcargv2 1 2
argv are :
argv[0] = ./argcargv2
argv[1] = 1
argv[2] = 2
$ ./argcargv2 1 2 34
argv are :
argv[0] = ./argcargv2
argv[1] = 1
argv[2] = 2
argv[3] = 34

综上,我们就可以写个bigger的demo程序了,先自己想想如何写。


代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*beginner/argcargv/argcargv3.c*/

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{

if (argc != 3)
{
printf("Usage :\n");
printf(" ./argcargv3 num1 num2\n");
exit(0);
}

if (atoi(argv[1]) > atoi(argv[2]))
printf("Bigger is %d\n", atoi(argv[1]));
else
printf("Bigger is %d\n", atoi(argv[2]));
return 0;
}

测试如下:

1
2
3
4
5
6
7
8
9
$ ./argcargv3
Usage :
./argcargv3 num1 num2

$ ./argcargv3 3 6
Bigger is 6

$ ./argcargv3 9 6
Bigger is 9

哇哦,又来了一点新东西,首先头文件加了stdlib,这个主要是因为使用了函数atoi,这个函数的含义就是把字符转换为数字,因为命令行参数的类型是char *的,所以在进行比较的时候要转换为整数。

编译运行

直接输入make就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#beginner/argcargv/Makefile
ALL : argcargv1 argcargv2 argcargv3

argcargv1: argcargv1.c
gcc -o argcargv1 argcargv1.c

argcargv2: argcargv2.c
gcc -o argcargv2 argcargv2.c

argcargv3: argcargv3.c
gcc -o argcargv3 argcargv3.c

.PHONY : clean

clean:
rm -f argcargv1 argcargv2 argcargv3