跳转到内容

shell脚本编程基础知识一

使用多个命令

在shell中可以输入多个命令,并输出不同命令的结果。甚至可以将一个命令的输出结果传递给另一个命令,可以将多个命令串联起来,一次执行完毕,而不是单独输入多次单个命令去执行。 如果想要多个命令一起执行,可以用;分号进行隔开,这样就能让多个命令随意串联在一起使用,但是需要注意命令行最大字符数是255,也就是说在终端命令行窗口中,最多只能输入255长度的命令。

Terminal window
date;who
#Sun May 4 09:34:56 CST 2025
#xiaobei console Apr 29 22:23
#xiaobei ttys002 May 4 09:34

创建shell脚本

创建shell脚本文件时,需要注意必须在文件的第一行指定要使用的shell,格式如下:

#!/bin/bash

在普通的shell脚本中#是用于注释,shell并不会处理脚本中的注释,但是shell脚本文件的第一行是个例外,#后面的惊叹号会让shell知道使用那个shell来运行脚本。

常见的shell有:

  • bash
  • zsh
  • fish
  • powershell

命令替换符号

bash中有2种方式,可以从命令输出中提取信息并赋值给bash变量。有如下两种形式:

  • 反引号(`)
  • $()

举例:

Terminal window
testing=`date`
# 2025年 5月 4日 星期日 01时02分05秒 CST
# 或者方式
testing=$(date)

需要注意:赋值符号与替换符号之间不能有空格

重定向输入和输出

作用是将命令的输出重定向到其他位置(比如文件)。重定向即可以用于输入,也可以用于输出,比如:将文件中的内容重定向为命令的输入。

输出重定向

语法:command > outputfile

使用大于符号>来实现输出重定向,例如:将ls -al命令的结果输入到test.txt文件中。

Terminal window
date > test.txt
# cat test.txt
#2025年 5月 4日 星期日 01时20分26秒 CST

注意:大于符号>每次都会将文件的内容进行覆盖。

Terminal window
who > test.txt
#cat test.txt
#xiaobei console 5 4 00:51
#xiaobei ttys000 5 4 01:01

如果你不想覆盖原来文件中的内容,而是在原来文件中进行内容的追加,则需要使用>> 双大于符号来表示。

举例:

Terminal window
date >> test.txt
#cat test.txt
#xiaobei console 5 4 00:51
#xiaobei ttys000 5 4 01:01
#2025年 5月 4日 星期日 01时26分24秒 CST

输入重定向

输入重定向是将文件的内容重定向到命令,输出重定向是命令的结果输出到文件,输入重定向是文件内容输出给命令。

语法:command < outputfile

使用小于符号<来实现输入重定向。与输出重定向的>>类似,也有<<内联输入重定向。

两者可以根据符号的方向来记忆到底是输出重定向还是输入重定向,因为两者的共性都是以命令开头,可以把输出重定向的大于符号>,看作是一个箭头符号,表示数据从命令流向到文件。输入重定向则反过来记忆,<就表示文件内容流向到命令。

管道

不知道你有没有遇到过这种情况,就是需要将一个命令的输出结果作为另一个命令的输入,按照上面说的,我们可以使用重定向来实现,但是会显得很笨拙,显得很啰嗦。

例如:

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

将rpm命令 + -qa参数,会生成使用rpm包管理器安装包的列表,但是这个列表并不是遵循某种特定的顺序,需要要找到具体某个rpm包是不太好找的。先通过重定向,将所有安装的rpm包使用输出重定向到rpm.list文件中,然后通过输入重定向,将rpm.list文件中的内容传递给sort命令对其进行排序,由sort命令按字母顺序对rpm包名称进行排序。

这种方式虽然管用,但是这个过程还是比较繁琐,又要重定向又要生成缓冲文件的,那有没有一种更简单方式?答案是有的,那就是使用管道。

什么是管道呢?管道一种将多个命令连接起来的机制,允许将一个命令的输出(stdout)直接作为另一个命令的输入(stdin),它通过符号|表示,是命令行操作中极其强大的工具。简而言之就是可以用来连接多个linux命令的。

管道能干什么呢?常见的管道操作场景如下:

  1. 过滤数据
Terminal window
# 查看当前目录下所有 ".txt" 文件
ls -l | grep ".txt"

ls 列出文件,grep 筛选出包含 “.txt” 的行。

  1. 统计信息
Terminal window
# 统计日志文件中 "ERROR" 出现的次数
cat app.log | grep "ERROR" | wc -l

cat 读取日志,grep 过滤关键字,wc -l 统计行数。

  1. 排序去重
Terminal window
# 对文件中的内容排序并去重
cat data.txt | sort | uniq

sort 排序,uniq 去重(需先排序)。

  1. 进程管理
Terminal window
# 查找并强制结束名为 "chrome" 的进程
ps aux | grep "chrome" | awk '{print $2}' | xargs kill -9

ps列出进程,grep筛选目标,awk提取进程ID,xargs传递参数给 kill

  1. 实时监控日志
Terminal window
# 实时跟踪日志并过滤关键信息
tail -f /var/log/syslog | grep "Failed"

tail -f持续输出日志内容,grep过滤特定关键词。

  1. 数据转换
Terminal window
# 将当前目录文件大小转换为 MB 显示
du -sh * | awk '{print $1/1024 " MB"}'

du获取文件大小,awk转换单位。

那上诉的案例重写如下:

Terminal window
rpm -qa | sort

是不是看起来都比上面的那种写法清爽很多。

管道可以连接的命令数量没有限制,可以持续的将命令的输出通过管道传递给其他命令来细化操作。

例如:

Terminal window
rpm -qa | sort | more

命令的含义,先执行rpm命令,将命令输出的结果传递给sort,然后sort命令排序好后,将排序好的顺序输出给more命令显示。

也可以结合输出重定向,将排序好的结果存到对应文件中。

Terminal window
rpm -qa | sort > rpm.list