# 简介

之前在 shell 快速入门中已经讲了如何构建一个脚本,我们回顾一下:

  • 第一行要指定 shell 类型 #!/bin/bash
  • 完成基本的脚本构建后,增加执行权限 chmod u+x 文件名(u是属主)
  • 要取消 echo 的换行,就要使用 -n 参数 echo -n "abcd"
  • 使用美元符号 $ 来引用变量,如果想单纯使用这个符号,要加上转义符 \$
  • 在脚本中自行设置变量时,= 之间不能有空格,不然 shell 会认为是命令而不是变量 var=100

本文会接着介绍其他与脚本编程相关的知识。

# 命令替换

shell 脚本最有用的特性之一就是可以从命令输出中提取信息,请 get 关键词,命令输出提取信息

该特性有两种实现方式:

  • 使用反引号(就是 Tab 键上面那个)
#date 命令可以得到当前时间 cyan@cyan-virtual-machine:~/Templates$ cat new_File
214391248
cyan@cyan-virtual-machine:~/Templates$ cat new_File
214391248
cyan@cyan-virtual-machine:~/Templates$ echo `date` > new_File
cyan@cyan-virtual-machine:~/Templates$ cat new_File
2022年 08月 01日 星期一 10:42:33 CST
cyan@cyan-virtual-machine:~$ var=`date`
cyan@cyan-virtual-machine:~$ echo $var
2022年 08月 01日 星期一 10:21:55 CST
  • 使用 $() ,有些 shell 不支持这种
cyan@cyan-virtual-machine:~$ var=$(date)
cyan@cyan-virtual-machine:~$ echo $var
2022年 08月 01日 星期一 10:23:19 CST

命令替换会创建一个子 shell 来运行对应命令,子 shell 是由运行脚本的 shell 创建的一个独立的子 shell 。因此,该子 shell 所执行的命令是无法使用脚本中所创建的变量的。在命令行提示符下使用路径./ 来运行命令,也会创建子 shell

关于 date 命令,你如果希望得到自己希望的格式化结果

cyan@cyan-virtual-machine:~$ date +%y-%m-%d\ %H:%M:%S
22-08-01 10:25:33

# 重定向

从这里开始,你就算接触流这个东西了,输入流输出流,重定向就是对流的方向重新定义(你现在可以这么理解)。

# 标准输出重定向

举一个例子, echo 将数据打印到屏幕上(标准输出流),那么我们可以对 echo 的流的方向重新指向

cyan@cyan-virtual-machine:~/Templates$ cat new_File
214391248
cyan@cyan-virtual-machine:~/Templates$ cat new_File
214391248
cyan@cyan-virtual-machine:~/Templates$ echo `date` > new_File
cyan@cyan-virtual-machine:~/Templates$ cat new_File
2022年 08月 01日 星期一 10:42:33 CST

从上面代码可以看到, echo 通过 > 符号,将输出重定向到 new_File 这个文件里面了。并且先清空文件原本内容

command >> outputfile 是追加模式。

# 标准输入重定向

将文件内容重定向到命令: command < inputfile

# wc 命令可以对数据文本进行计数:文本行数  文本字数  文本字节数
cyan@cyan-virtual-machine:~/Templates$ wc < new_File
 1  6 43

这里有个需要注意的地方就是, < 是改变标准输出(屏幕), > 是改变标准输入(键盘)。重定向不是代替参数,而是改变标准输入输出

比如以下命令就不行

echo < new_File

echo 的使用格式是 echo 参数 ,重定向不能替代参数。

wc 后面接收的可以是标准输入

cyan@cyan-virtual-machine:~/Templates$ wc
line1
line2
      2       2      12 # 使用 ctrl+d 结束命令并统计

# 内联重定向

可以参考:https://blog.csdn.net/qq_38156104/article/details/110375889

替换文件为文本,数据流向命令: command << 特殊字符

数据的开始和结束文本标记要一致。本质就是将开始符和结束符之间的数据传给命令

cyan@cyan-virtual-machine:~/Templates$ wc <<EOF
> 123
> 4142
> EOF
2 2 9

# 管道

一个命令的标准输出作为另一个命令的标准输入

rpm -qa > rpm.list
sort < rpm.list

rpm 命令通过 RedHat 包管理系统 ( RPM ) 对系统上安装的软件包进行管理。配合 -qa 选项使用时,会生成已安装包的列表,尽管不会排序。(虽然我在终端执行上面两个命令没啥反应)

重定向在命令之间数据传输比较繁琐,使用管道 | 解决。

command | command

为了更好了解管道,我写了一个 c 程序,文件为 test.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <fcntl.h>
int main()
{
        struct timeval start,end;
        int fd = open("./tmp",O_RDONLY);
        int i = 0;
        char bf[10];
        for(i;i < 10;i++)
        {
                gettimeofday(&start,NULL);
                read(fd,bf,10);
                gettimeofday(&end,NULL);
                //printf("%s",bf);
                printf("%d",end.tv_usec - start.tv_usec);
        }
        close(fd);
        return 0;
}

linux 中可以用 cat 查看,如果在后面接上 sort 命令

cat test.c | sort

其输出结果为

{
        }
{
}
        char bf[10];
        close(fd);
        for(i;i < 10;i++)
                gettimeofday(&end,NULL);
                gettimeofday(&start,NULL);
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
        int fd = open("./tmp",O_RDONLY);
        int i = 0;
int main()
                printf("%d",end.tv_usec - start.tv_usec);
                //printf("%s",bf);
                read(fd,bf,10);
        return 0;
        struct timeval start,end;