当前位置:   article > 正文

7.1.3、Shell 命令的基本格式_shell命令格式

shell命令格式

关注公众号 “融码一生”,领取全套 PDF / 电子书

  • 进入 Shell 之后第一眼看到的内容类似如下:
  1. # root 用户登录看到的是:
  2. [root@VM-4-13-centos ~]#
  3. # 普通用户登录看到的是:
  4. [test1@VM-4-13-centos ~]$
  • 这叫命令提示符,看见它就意味着可以输入命令。命令提示符不是命令的一部分,它只起到一个提示作用。
  • Shell 命令的基本格式:
    • command [选项] [参数]
      • []表示可选(可有可无)。有些命令不写选项和参数也能执行,有些命令在必要的时可以附带选项和参数。
      • 选项:调整命令功能。如果没有选项,命令只能执行最基本的功能;有选项则能执行更多功能,或显示更丰富的数据。
        • Linux 的选项又分为:
          • 短格式选项:用减号-和一个字母表示,如ls -l
          • 长格式选项:完整的英文单词,用两个减号--和一个单词表示,如ls --all
        • 一般情况下,短格式选项是长格式选项的缩写(一个短格式选项会有对应的长格式选项)。也有例外,比如ls命令的短格式选项-l就没有对应的长格式选项。
      • 参数:命令的操作对象,一般情况下,文件、目录、用户和进程等都可以作为参数被命令操作。如:ls -l main.c
        • 但为什么ls命令可以省略参数?因为有默认参数。命令一般都需要加入参数,用于指定命令操作的对象。如果省略参数,则一般都有默认参数。
  • 有些命令的选项后面也可以附带参数,这些参数用来补全选项,或调整选项的功能细节。
  • 例如,read命令用来读取用户输入的数据,并把读取到的数据赋值给一个变量,通常的用法为:
    • read str
      • str:变量名
  • 如果只是想读取固定长度的字符串,可以给read命令增加-n选项。比如读取一个字符作为性别的标志,可以这样写:
    • read -n 1 sex
      • 1-n选项的值;-n选项表示读取固定长度的字符串,它后面必然要跟一个数字用来指明长度,否则选项是不完整的
      • sexread命令的参数

1、Shell 命令的本质、如何自己实现一个命令?

  • 用户通过在 Shell 中输入一些命令来使用 Linux。给命令附带不同的选项后,同一个命令的功能也会有所差异。
  • Shell 命令分为两种:
    • Shell 自带的命令称为内置命令,它在 Shell 内部可以通过函数来实现,当 Shell 启动后,这些命令所对应的代码(函数体代码)也被加载到内存中,所以使用内置命令是非常快速的。
    • 更多的命令是外部的应用程序,一个命令就对应一个应用程序。运行外部命令要开启一个新的进程,所以效率上比内置命令差很多。
  • 用户输入一个命令后,Shell 先检测该命令是不是内置命令,如果是就执行,如果不是就检测有没有对应的外部程序:有的话就转而执行外部程序,执行结束后再回到 Shell;没有的话就报错,告诉用户该命令不存在。

(1)内置命令

  • 内置命令不宜过多,过多的内置命令会导致 Shell 程序本身体积膨胀,运行 Shell 程序后就会占用更多的内存。Shell 是一个常驻内存的程序,占用过多内存会影响其它的程序。
  • 只有那些最常用的命令才有理由成为内置命令,如 cd、kill、echo 等。

(2)外部命令

  • 应用程序就是一个文件,只不过这个文件是可执行的。既然是文件,那么它就有一个名字,并且存放在文件系统中。用户在 Shell 中输入一个外部命令后,只是将可执行文件的名字告诉 Shell,并没有告诉 Shell 去哪寻找这个文件。
  • Shell 在启动文件中增加了一个叫 PATH 的环境变量,该变量就保存了 Shell 对外部命令的查找路径,如果在这些路径下找不到同名的文件,Shell 也不会再去其它路径下查找了,它就直接报错。
  • 使用 echo 命令输出 PATH 变量的值,看看它保存了哪些检索路径:
  1. echo $PATH
  2. :<<!
  3. /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
  4. !
  • 不同的路径之间以:分隔。
  • 如果用 C/C++ 编写一个应用程序,并将它放到这几个目录下,则我们的程序也会成为 Shell 命令。也可以修改 PATH 变量给它增加另外的路径。
  • 示例:使用 C 语言编写了一个叫 getsum 的程序,计算从 m 累加到 n 的和:
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <getopt.h>
  4. #include <stdlib.h>
  5. int main(int argc, char *argv[]){
  6. int start = 0;
  7. int end = 0;
  8. int sum = 0;
  9. int opt;
  10. char *optstring = ":s:e:";
  11. while((opt = getopt(argc, argv, optstring))!= -1){
  12. switch(opt){
  13. case 's': start = atoi(optarg); break;
  14. case 'e': end = atoi(optarg); break;
  15. case ':': puts("Missing parameter"); exit(1);
  16. }
  17. }
  18. if(start<0 || end<=start){
  19. puts("Parameter error"); exit(2);
  20. }
  21. for(int i=start; i<=end; i++){
  22. sum+=i;
  23. }
  24. printf("%d\n", sum);
  25. return 0;
  26. }
  • 将这段代码编译成名为 getsum 的应用程序,并放在~/bin目录(~表示用户主目录)下,然后在 Shell 中输入下面的命令,就可以计算 1+2+3 ...... +99+100 的值。
  1. gcc getsum.c -o getsum -std=c99
  2. mkdir ~/bin
  3. mv getsum ~/bin
  4. # -s 选项表示起始数字, -e 选项表示终止数字
  5. getsum -s 1 -e 100
  6. :<<!
  7. 5050
  8. !
  • Shell 内置命令的本质是一个自带的函数,执行内置命令就是调用这个自带的函数。因为函数代码在 Shell 启动时已经被加载到内存,所以内置命令的执行速度很快。
  • Shell 外部命令的本质是一个应用程序,执行外部命令就是启动一个新的应用程序。因为要创建新的进程并加载应用程序的代码,所以外部命令的执行速度很慢。

2、Shell 命令的选项和参数的本质

  • 很多 Shell 命令都可以附带选项和参数的,不同的选项和参数也使得命令的功能细节有所差异。
  • Shell 命令附带参数:
    • cd demo:进入当前目录下的 demo 目录,demo就是 cd 命令的参数
    • echo "123xyz":输出字符串并换行,"123xyz"就是 echo 命令的参数
  • Shell 命令附带选项:
    • ls -l:显示当前目录下的所有文件以及它们的详细信息;-l就是ls命令的选项
    • echo -n "hello world":在输出字符串后不换行;-n是 echo 命令的选项,"hello world"是 echo 命令的参数
  • 有些命令的选项后面也可以附带参数:
    • getsum -s 1 -e 100:计算从 1 累加到 100 的和;-s-e是 getsum 命令的选项,1100分别是-s-e选项的参数
    • read -n 1 sex:读取一个字符并赋值给 sex 变量;-n是 read 命令的选项,1-n选项的参数,sexread命令的参数
  • 一个 Shell 内置命令就是一个内部的函数,一个外部命令就是一个应用程序。
    • 内置命令后面附带的所有数据(选项和参数)最终都以参数的形式传递给函数
    • 外部命令后面附带的所有数据(选项和参数)最终都以参数的形式传递给应用程序
    • 不管是内置命令还是外部命令,它后面附带的所有数据都会被“打包”成参数,这些参数有的传递给了函数,有的传递给了应用程序。
  • C/C++ 程序的入口函数是int main(int argc, char *argv[]),传递给应用程序的参数最终都被 main 函数接收了。从这个角度看,传递给应用程序的参数其实也是传递给了函数。
  • 有了以上认知,就不用再区分函数和应用程序了,我们就认为:不管是内置命令还是外部命令,它后面附带的数据最终都以参数的形式传递给函数。实现一个命令的一项重要工作就是解析传递给函数的参数。
  • 注意:命令后面附带的数据并不是被合并在一起作为一个参数传递给函数的;这些数据由空格分隔,它们被分隔成了几份,就会转换成几个参数。例如getsum -s 1 -e 100要向函数传递四个参数,read -n 1 sex要向函数中传递三个参数。
  • 命令后面附带的数据都是“原汁原味”地传递给了函数,比如getsum -s 1 -e 100要传递的四个参数分别是 -s、1、-e、100,减号-也会一起传递过去;在函数内部,减号-可以用来区分该参数是否是命令的选项。
  • 至于在函数内部如何解析这些参数,对于外部命令来说就是 C/C++ 程序员的工作了。
  • 使用getsum程序演示参数的解析:
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <getopt.h>
  4. #include <stdlib.h>
  5. int main(int argc, char *argv[]){
  6. int start = 0;
  7. int end = 0;
  8. int sum = 0;
  9. int opt;
  10. char *optstring = ":s:e:";
  11. // 分析接收到的参数
  12. // getopt.h 头文件中的 getopt() 函数值得重点, 有了该函数就不用自己去解析参数;
  13. while((opt = getopt(argc, argv, optstring))!= -1){
  14. switch(opt){
  15. case 's': start = atoi(optarg); break;
  16. case 'e': end = atoi(optarg); break;
  17. case ':': puts("Missing parameter"); exit(1);
  18. }
  19. }
  20. // 检测参数是否有效
  21. if(start<0 || end<=start){
  22. puts("Parameter error"); exit(2);
  23. }
  24. // 打印接收到的参数(将接收到的参数打印出来, 以便读者更好地观察)
  25. printf("Received parameters: ");
  26. for(int i=0; i<argc; i++){
  27. printf("%s ", argv[i]);
  28. }
  29. printf("\n");
  30. // 计算累加的和
  31. for(int i=start; i<=end; i++){
  32. sum+=i;
  33. }
  34. printf("sum=%d\n", sum);
  35. return 0;
  36. }
  • 编译并运行 getsum 命令:
  1. gcc getsum.c -o getsum -std=c99
  2. mkdir ~/bin
  3. mv getsum ~/bin
  4. getsum -s 1 -e 100
  5. :<<!
  6. Received parameters: getsum -s 1 -e 100
  7. sum=5050
  8. !

3、Shell 命令提示符

  • 启动 Linux 桌面环境自带的终端模拟包或从 Linux 控制台登录后,便可以看到 Shell 命令提示符,意味着可以输入命令了。命令提示符不是命令的一部分,它只是起到提示作用。
  • 不同的 Linux 发行版使用的提示符格式大同小异,例如在 CentOS 中默认的提示符类似如下:
  1. # root 用户登录看到的是:
  2. [root@VM-4-13-centos ~]#
  3. # 普通用户登录看到的是:
  4. [test1@VM-4-13-centos ~]$
  5. [test1@VM-4-13-centos ~]$ cd demo
  6. [test1@VM-4-13-centos demo]$ cd /usr/local
  7. [test1@VM-4-13-centos local]$
  8. # 总结起来, Linux Shell 默认的命令提示符的格式为:
  9. [username@host directory]$
  10. [username@host directory]#
  • []:提示符的分隔符号,没有特殊含义
  • test1:当前登录的用户
  • @:分隔符号,没有特殊含义
  • VM-4-13-centos:当前系统的简写主机名
  • ~:用户当前所在的目录为主目录(home 目录)
    • 超级用户的主目录为/root/,普通用户的主目录为/home/用户名/
    • 如果用户当前位于主目录下的 bin 目录中,则显示的就是bin
    • 如果切换用户所在目录,则命令提示符中会变成用户当前所在目录的最后一个目录(不显示完整的所在目录/usr/local/,只显示最后一个目录local
  • $是命令提示符。Linux 用这个符号标识登录的用户权限等级
    • 超级用户(root 用户)的提示符是#
    • 普通用户提示符是$

第二层命令提示符

  • 有些命令不能在一行内输入完成,需换行,这时会看到第二层命令提示符,默认为>
  1. [root@VM-4-13-centos ~]$ echo "Shell 教程"
  2. :<<!
  3. Shell 教程
  4. !
  5. [root@VM-4-13-centos ~]$ echo "
  6. > http://
  7. > baidu.com
  8. > "
  9. :<<!
  10. http://
  11. baidu.com
  12. !
  • 第一个 echo 命令在一行内输入完成,不会出现第二层提示符。
  • 第二个 echo 命令需要多行才能输入完成,提示符>用来告诉用户命令还没输入完成,请继续输入。
  • echo 命令用来输出一个字符串。字符串是一组由" "包围起来的字符序列,echo 将第一个"作为字符串的开端,将第二个"作为字符串的结尾。
  • 第二个 echo 命令中将字符串分成多行,echo 遇到第一个"认为是不完整的字符串,所以会继续等待用户输入,直到遇见第二个"

4、Shell 修改命令提示符

  • Shell 通过PS1PS2这两个环境变量来控制提示符的格式,修改PS1PS2的值就能修改命令提示符的格式。
    • PS1控制最外层的命令提示符格式
    • PS2控制第二层的命令提示符格式
  1. [root@VM-4-13-centos ~]# echo $PS1
  2. :<<!
  3. [\u@\h \W]\$
  4. !
  5. [root@VM-4-13-centos ~]# echo $PS2
  6. :<<!
  7. >
  8. !
  • Linux 使用以\为前导的特殊字符来表示命令提示符中包含的要素,这使得PS1PS2的格式看起来可能有点奇怪。
  • 可以在PS1PS2中使用的特殊字符:

字符

描述

\a

铃声字符

\d

格式为“日 月 年”的日期

\e

ASCII 转义字符

\h

本地主机名

\H

完全合格的限定域主机名

\j

shell 当前管理的作业数

\1

shell 终端设备名的基本名称

\n

ASCII 换行字符

\r

ASCII 回车

\s

shell 的名称

\t

格式为“小时:分钟:秒”的 24 小时制的当前时间

\T

格式为“小时:分钟:秒”的 12 小时制的当前时间

\@

格式为 am/pm 的 12 小时制的当前时间

\u

当前用户的用户名

\v

bash shell 的版本

\V

bash shell 的发布级别

\w

当前工作目录

\W

当前工作目录的基本名称

\!

该命令的 bash shell 历史数

\#

该命令的命令数量

\$

如果是普通用户,则为美元符号$;如果超级用户(root 用户),则为井号#

\nnn

对应于八进制值 nnn 的字符

\\

斜杠

\[

控制码序列的开头

\]

控制码序列的结尾

  • 注意:所有特殊字符均以反斜杠\开头,目的是与普通字符区分开。可以在命令提示符中使用以上任何特殊字符的组合。
  • 示例:通过修改PS1变量的值来修改命令提示符的格式:
  1. [root@VM-4-13-centos ~]# PS1="[\t][\u]\$ "
  2. [15:06:32][root]$ PS1="[www.baidu.com]\$ "
  3. [www.baidu.com]$
  • 通过这种方式修改的命令提示符只在当前的 Shell 会话期间有效,再次启动 Shell 后将重新使用默认的命令提示符。
  • 如果希望持久性地修改 PS1,让它对任何 Shell 会话都有效,就得把 PS1 变量的修改写入到 Shell 启动文件中。

关注公众号 “融码一生”,领取全套 PDF / 电子书

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/914113
推荐阅读
相关标签
  

闽ICP备14008679号