Shell编程规范与Shell中的管道符号(|)和重定向符号<、>、>>

Shell脚本的应用场景

Shell脚本(Shell Script)就是要执行的命令按顺序保存到一个文本文件,并给该文件可执行权限,方便一次性执行的一个程序文件。主要是方便管理员进行设置或管理,可结合各种Shell控制语句以完成更复杂的操作。常用于重复性操作、批量事务处理、自动化运维、服务运行状态监控、定时任务执行等。
在一些复杂的Linux维护工作中,大量重复性的输入和交互操作不但费时费力,而且容易出错,而编写一个恰到好处的Shell脚本程序,可以批量处理、自动化地完成一系列维护任务,大大减轻管理员的负担。
像网站发布脚本,每天登陆网站,我们会发现每页内容,并不是一成不变的,正常情况下网站会根据开发人员开发完成的代码定期更新网站的内容,称之为网站定期发布新版本。但是对于一些跟新间隔比较短的网站,手动执行命令发布是一种重复性的操作,很浪费时间,又比较麻烦。为解决此问题可以开发一个自动发布的版本,就可以高效准确、轻松自如地一键发布脚本了

Shell编程规范

Linux系统中的Shell脚本是一个特殊的应用程序,它介于操作系统内核与用户之间,充当一个翻译官的角色,负责接收用户输入的操作命令并进行解释,将需要执行的操作传递给内核执行,并输出执行结果

1、Shell解释器程序的种类

1、Shell解释器程序的种类
常见的额Shell解释器程序有很多种类,使用不同的Shell脚本时,其内部指令、命令行提示等方面的会存在一些区别。通过/etc/shells文件可以了解当前系统所支持的Shell脚本种类。
其中,/bin/bash是目前大多数Linux版本采用的默认Shell脚本。Bash的全称为Bourne Again Shell,是目前最受欢迎的开源软件项目之一。

[root@localhost ~]# cat /etc/shells    //当前系统所支持的Shell脚本种类
/bin/sh
/bin/bash         //最受欢迎的开源软件项目之一
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh

2、编写一个简单的Shell脚本

[root@localhost ~]# vi myfirst.sh   //创建编辑一个以.sh结尾的文件
#!/bin/bash
#一个简单的Shell脚本        //“#”用于注释的内容
cd/opt/                                    //切换到opt目录
echo "当前位于哪个目录:"    //在屏幕显示“ ....... ”
pwd                                          //查看当前在那个目录中
echo "查看当前目录:"      
ls -lh                                         //查看当前目录内容 

3、执行脚本文件的方式

先给编写好的脚本文件可执行权限

[root@localhost ~]# chmod +x myfirst.sh     //给文件添加执行的权限

3.1、根据脚本文件的路径 (相对路径与绝对路径)

[root@localhost ~]# ./myfirst.sh    //或  .ceshi.sh 前提是在执行文件的目录下
当前位于哪个目录:
/opt
查看当前目录:
总用量 0
drwxr-xr-x. 2 root root 6 3月  26 2015 rh

3.2、sh 脚本文件路径

[root@localhost /]# sh /root/myfirst.sh  //执行脚本
当前位于哪个目录:
/opt
查看当前目录:
总用量 0
drwxr-xr-x. 2 root root 6 3月  26 2015 rh

3.3、Source 脚本文件路径

[root@localhost /]# source /root/myfirst.sh  //刷新执行脚本
当前位于哪个目录:
/opt
查看当前目录:
总用量 0
drwxr-xr-x. 2 root root 6 3月  26 2015 rh

4、Shell环境中的:管道(|)与重定向(< 、>、>>)

由于Shell脚本批零处理的特殊性,其大部分操作过程位于后台,不需要用户进行干预。因此学会提取、过滤执行信息变得十分重要。

4.1、管道符号( | )应用

管道操作作为不同命令之间的协同工作提供了一种机制,位于管道符号“ | ”左侧的命令输出的结果,将作为右侧命令的输入(处理对象),同一行命令中可以使用多个管道。

cmd1  命令1 |  cmd2  命令2  [... | cmdn 命令 n]   //管道符号的使用格式。22

在 Shell 脚本应用中,管道操作通常用来过滤所需要的关键信息。例如,使用 grep 命令查用/bin/bash 作为 Shell 的系统用户名时,会输出符合条件的整行内容,在此基础上可以结合管道操作与 awk 命令做进一步过滤,只输出用户名和登录 Shell。

[root@localhost opt]# grep "/bin/bash$" /etc/passwd    //过滤文件中以/bin/bash结尾的行
root:x:0:0:root:/root:/bin/bash
[root@localhost opt]# grep "/bin/bash$" /etc/passwd | awk -F: '{print $1,$7}'      
        //过滤该行以冒号分割的第一位与第七位
root /bin/bash
[root@localhost opt]# free -m    //查看内存使用使用情况
total 内存总数:7806M
used 已经使用的内存数: 463M
free 空闲的内存数: 6760M
shared 当前已经废弃不用,总是10M
buffers Buffer 缓存内存数: 582M
cached Page 缓存内存数:582M
available     实际可用的内存数:7055M
              total        used        free      shared  buff/cache   available
Mem:           7806         463        6760          10         582        7055
Swap:          8063           0        8063

4.2、重定向符号(< 、>、>>)应用

Linux 系统使用文件来描述各种硬件、设备等资源,如以前学过的硬盘和分区、光盘等设备文件。用户通过操作系统处理信息的过程中,包括以下几类交互设备文件。

标准输入(STDIN):默认的设备是键盘,文件编号为 0,命令将从标准输入文件中读取在执行过程中需要的输入数据。

标准输出(STDOUT):默认的设备是显示器,文件编号为 1,命令将执行后的输出结果发送到标准输出文件。

标准错误(STDERR):默认的设备是显示器,文件编号为 2,命令将执行期间的各种错误信息发送到标准错误文件。

标准输入、标准输出和标准错误默认使用键盘和显示器作为关联的设备,与操作系统进 行交互,完成最基本的输入、输出操作,即从键盘接收用户输入的各种命令字串、辅助控制 信息,并将命令结果输出到屏幕上;如果命令执行出错,也会将错误信息反馈到屏幕上。

在实际的 Linux 系统维护中,可以改变输入、输出内容的方向,而不使用默认的标准输入、输出设备(键盘和显示器),这种操作称为重定向。

4.2.1、重定向输出

重定向输出指的是将命令的正常输出结果保存到指定的文件中,而不是直接显示在显示 器的屏幕上。重定向输出使用“>”或“>>”操作符号,分别用于覆盖或追加文件。

若重定向输出的目标文件不存在,则会新建该文件,然后将前面命令的输出结果保存到该文件中;若目标文件已经存在,则将输出结果覆盖或追加到文件中。例如,若要将当前主机的 CPU 类型信息(uname -p)保存到 kernel.txt 文件中,而不是直接显示在屏幕上,可以执行以下操作。

[root@localhost ~]# uname -p > kernel.txt
[root@localhost ~]# cat kernel.txt
x86_64

当需要保留目标文件原有的内容时,应改用“> ”操作符号,以便追加内容而不是全部覆盖。例如,执行以下操作可以将内核版本信息追加到 kernel.txt 文件中。

[root@localhost ~]# uname -r >> kernel.txt    
[root@localhost ~]# cat kernel.txt
x86_64
3.10.0-514.el7.x86_64

4.2.2、重定向输入

重定向输入指的是将命令中接收输入的途径由默认的键盘改为指定的文件,而不是等待 从键盘输入。重定向输入使用“<”操作符。

通过重定向输入可以使一些交互式操作过程能够通过读取文件来完成。例如,使用passwd 命令为用户设置密码时,每次都必须根据提示输入两次密码字串,非常烦琐,若改用重定向输入将可以省略交互式的过程,而自动完成密码设置(结合 passwd 命令的“–stdin” 选项来识别标准输入)。

[root@localhost ~]# vim pass.txt	//添加初始密码串内容"123456" 123456
[root@localhost ~]# passwd --stdin jerry < pass.txt
//从pass.txt 文件中取密码,需要注意 SELinux 会影响此命令执行,若执行失败可尝试关闭 SELinux 
Changing password for user jerry.
passwd: all authentication tokens updated successfully.

非交互式命令语句可以更方便的在 Shell 脚本中使用,从而大大减少程序被打断的过程, 提高脚本执行的效率。

4.2.3、错误重定向

错误重定向指的是将执行命令过程中出现的错误信息(如选项或参数错误等)保存到指定的文件,而不是直接显示在屏幕上。错误重定向使用“2>”操作符,其中“2”是指错误文件的编号(在使用标准出、标准输入重定向时,实际上省略了 1、0 编号)。

在实际应用中,错误重定向可用来收集程序执行的错误信息,为排错提供依据;对于Shell 脚本,还可以将无关紧要的错误信息重定向到空文件/dev/null 中,以保持脚本输出的简洁。例如,执行以下操作可以将使用 tar 命令进行备份时出现的错误信息保存到 error.log 文件中。

[root@localhost ~]# tar jcf /nonedir/etc.tgz /etc/ 2> error.log
[root@localhost ~]# cat error.log
tar: Removing leading `/' from member namestar (child): /nonedir/etc.tgz: Cannot open
: No such file or directory
tar (child): Error is not recoverable: exiting now

使用“2>”操作符时,会像使用“>”操作符一样覆盖目标文件的内容,若要追加内容而不是覆盖文件,则应改用“2>>”操作符。

当命令输出的结果可能既包括标准输出(正常执行)信息,又包括错误输出信息时,可 以使用操作符“>”“2>”将两类输出信息分别保存到不同的文件,也可以使用“&>”操作符将两类输出信息保存到同一个文件。例如,在编译源码包的自动化脚本中,若要忽略 make、make install 等操作过程信息,则可以将其定向到空文件/dev/null。

[root@localhost ~]# vim httpd_install.sh
#!/bin/bash
# 自动编译安装httpd 服务器的脚本
cd /usr/src/httpd-2.4.25/
./configure --prefix=/usr/local/httpd --enable-so &> /dev/null make &> /dev/null
make install &> /dev/null
…… //省略部分内容
[root@localhost ~]# chmod +x httpd_install.sh
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Linux ,使用 C 语言模拟 shell 命令可以通过调用系统函数实现。以下是一个简单的例子,演示了如何使用 C 语言实现重定向管道通信。 首先,我们需要包含一些头文件: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> ``` 接下来,我们可以定义一些常量,例如: ```c #define MAX_ARGS 10 #define MAX_BUFFER 1024 ``` 然后,我们可以定义一个函数来解析用户输入的命令,并将其分解为单个参数。以下是一个简单的实现: ```c void parse_command(char *command, char **args, int *redirect_input, int *redirect_output) { int arg_count = 0; char *token; char *rest = command; while ((token = strtok_r(rest, " ", &rest))) { if (*token == '<') { *redirect_input = open(token + 1, O_RDONLY); } else if (*token == '>') { *redirect_output = open(token + 1, O_WRONLY | O_CREAT | O_TRUNC, 0644); } else { args[arg_count++] = token; } } args[arg_count] = NULL; } ``` 此函数通过使用 `strtok_r()` 函数将命令分解为参数。如果命令包含输入重定向符 `<`,则将 `redirect_input` 指针设置为打开输入文件的文件描述符。如果命令包含输出重定向符 `>`,则将 `redirect_output` 指针设置为打开输出文件的文件描述符。在解析完成后,参数将存储在 `args` 数组。 接下来,我们可以定义一个函数来处理管道通信。以下是一个简单的实现: ```c void pipe_commands(char **commands) { int fd[2]; pid_t pid1, pid2; char *args1[MAX_ARGS], *args2[MAX_ARGS]; if (pipe(fd) == -1) { perror("pipe"); exit(EXIT_FAILURE); } parse_command(commands[0], args1, NULL, &fd[1]); parse_command(commands[1], args2, &fd[0], NULL); pid1 = fork(); if (pid1 == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid1 == 0) { close(fd[0]); dup2(fd[1], STDOUT_FILENO); close(fd[1]); execvp(args1[0], args1); } else { pid2 = fork(); if (pid2 == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid2 == 0) { close(fd[1]); dup2(fd[0], STDIN_FILENO); close(fd[0]); execvp(args2[0], args2); } else { close(fd[0]); close(fd[1]); wait(NULL); wait(NULL); } } } ``` 此函数创建一个管道,然后使用 `parse_command()` 函数解析两个命令,并将其分别存储在 `args1` 和 `args2` 数组。接下来,它调用 `fork()` 函数创建两个子进程,其一个子进程执行第一个命令,另一个子进程执行第二个命令。使用 `dup2()` 函数将子进程的标准输出或标准输入连接到管道的适当端口。最后,主进程等待两个子进程完成。 最后,我们可以定义一个主函数来使用这些函数来执行用户输入的命令。以下是一个简单的实现: ```c int main() { char buffer[MAX_BUFFER]; char *commands[2]; int redirect_input = 0, redirect_output = 0; while (1) { printf("$ "); if (fgets(buffer, MAX_BUFFER, stdin) == NULL) break; commands[0] = strtok(buffer, "|"); if ((commands[1] = strtok(NULL, "\n")) != NULL) { pipe_commands(commands); } else { parse_command(commands[0], commands, &redirect_input, &redirect_output); pid_t pid = fork(); if (pid == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid == 0) { if (redirect_input) { dup2(redirect_input, STDIN_FILENO); close(redirect_input); } if (redirect_output) { dup2(redirect_output, STDOUT_FILENO); close(redirect_output); } execvp(commands[0], commands); } else { wait(NULL); } } } return 0; } ``` 此函数使用 `fgets()` 函数从标准输入读取用户输入的命令。如果命令包含管道符 `|`,则使用 `strtok()` 函数将命令分解为两个命令,并使用 `pipe_commands()` 函数执行它们之间的管道通信。否则,就使用 `parse_command()` 函数解析命令,并使用 `fork()` 函数创建子进程来执行命令。在子进程,使用 `dup2()` 函数将标准输入或标准输出重定向到适当的文件描述符。最后,主进程使用 `wait()` 函数等待子进程完成。 这就是使用 C 语言模拟 shell 命令的基本方法。请注意,此实现仅用于演示目的,并且可能需要进行更改以处理更多情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值