
Shell 一直是类 Unix 系统的核心命令行解释器,也是 Linux 强大功能的关键体现。常见的 Shell 如 Bash、Zsh 等,不仅提供了丰富的命令,其可编程性更允许我们通过编写脚本来自动化处理日常工作,极大提升效率。下面通过 40 个示例来快速掌握 Shell 脚本编程。
1. Hello World
学习任何新语言都从“Hello World”开始。创建一个名为 hello-world.sh 的文件,并写入以下内容:
#!/bin/bash
echo "Hello World"
保存后,需要赋予文件执行权限:
$ chmod a+x hello-world.sh
运行脚本有两种方式:
$ bash hello-world.sh
$ ./hello-world.sh
脚本会输出字符串 “Hello World”。
2. 使用 echo 打印
echo 命令用于在终端打印信息,支持转义序列和输出控制。创建一个 echo.sh 脚本:
#!/bin/bash
echo "Printing text"
echo -n "Printing text without newline"
echo -e "\nRemoving \t special \t characters\n"
运行脚本查看效果。-n 选项可以取消输出末尾的换行符,-e 选项则允许解析字符串中的转义字符(如 \n 换行、\t 制表符)。
3. 使用注释
注释是编写高质量、可维护代码的基础。在 Shell 脚本中,使用 # 符号来添加单行注释。
#!/bin/bash
# 这是注释:计算两个数的和
((sum=25+35))
# 打印结果
echo $sum
这段脚本将输出数字 60。注意第一行的 #!/bin/bash 是一个特例,它称为 “shebang”,用于指定执行此脚本的解释器路径。
4. 多行注释
Shell 本身没有专门的多行注释语法,但可以通过一些小技巧实现。下面是一个名为 comment.sh 的示例:
#!/bin/bash
: '
这是一个多行注释。
本脚本用于计算数字 5 的平方。
'
((area=5*5))
echo $area
多行注释内容被包裹在 : ‘ 和 ’ 符号之间。
5. While 循环
while 循环用于重复执行一段代码,直到条件不再满足。查看 while.sh 脚本:
#!/bin/bash
i=0
while [ $i -le 2 ]
do
echo Number: $i
((i++))
done
while 循环的基本结构如下,注意方括号 [ ] 内的空格是必需的:
while [ condition ]
do
commands
done
6. For 循环
for 循环是另一种高效的迭代结构。下面是一个打印 1 到 10 的简单示例:
#!/bin/bash
for (( counter=1; counter<=10; counter++ ))
do
echo -n "$counter "
done
printf "\n"
7. 接收用户输入
使用 read 命令可以获取用户的输入。
#!/bin/bash
echo -n "Enter Something:"
read something
echo "You Entered: $something"
8. If 语句
if 语句用于条件判断,其基本语法为:
if CONDITION
then
STATEMENTS
fi
只有当条件为真时,then 和 fi 之间的语句才会执行。下面是一个示例:
#!/bin/bash
echo -n “Enter a number: ”
read num
if [[ $num -gt 10 ]]
then
echo “Number is greater than 10.”
fi
如果输入的数字大于 10,则会显示输出。这里 -gt 表示大于;类似地,-lt 小于,-le 小于等于,-ge 大于等于。条件判断使用双中括号 [[ ]]。
9. 使用 If Else 进行更多控制
结合 else 可以使逻辑更加完整。
#!/bin/bash
read n
if [ $n -lt 10 ];
then
echo “It is a one digit number”
else
echo “It is a two digit number”
fi
else 部分需要放在 if 的语句块之后,fi 之前。
10. 使用 AND 运算符
AND 运算符 && 用于检查多个条件是否同时成立。
#!/bin/bash
echo -n “Enter Number:”
read num
if [[ ( $num -lt 10 ) && ( $num%2 -eq 0 ) ]]; then
echo “Even Number”
else
echo “Odd Number”
fi
只有数字小于 10 并且 是偶数时,才会输出 “Even Number”。
11. 使用 OR 运算符
OR 运算符 || 在多个条件中,只要有一个为真则整体为真。
#!/bin/bash
echo -n “Enter any number:”
read n
if [[ ( $n -eq 15 || $n -eq 45 ) ]]
then
echo “You won”
else
echo “You lost!”
fi
只有当用户输入数字 15 或 45 时,才会宣布获胜。
12. 使用 Elif
elif 代表 “else if”,用于实现链式的条件判断。
#!/bin/bash
echo -n “Enter a number: ”
read num
if [[ $num -gt 10 ]]
then
echo “Number is greater than 10.”
elif [[ $num -eq 10 ]]
then
echo “Number is equal to 10.”
else
echo “Number is less than 10.”
fi
13. case 条件
当条件分支较多时,使用 case 语句比多个 if-elif 更清晰。
#!/bin/bash
echo -n “Enter a number: ”
read num
case $num in
100)
echo “Hundred!!” ;;
200)
echo “Double Hundred!!” ;;
*)
echo “Neither 100 nor 200” ;;
esac
条件分支写在 case 和 esac 关键字之间。*) 模式用于匹配所有其他情况。
14. 命令行参数
直接从命令行向脚本传递参数非常有用。特殊变量 $1, $2... 可以获取这些参数。
#!/bin/bash
echo “Total arguments : $#”
echo “First Argument = $1”
echo “Second Argument = $2”
将脚本命名为 test.sh 并按如下方式调用:
$ ./test.sh Hey Howdy
$1 对应第一个参数 “Hey”,$2 对应第二个参数 “Howdy”。$# 则用于获取参数的总个数。
15. 使用名称获取参数
可以通过键值对的形式传递具名参数。
#!/bin/bash
for arg in “$@”
do
index=$(echo $arg | cut -f1 -d=)
val=$(echo $arg | cut -f2 -d=)
case $index in
X) x=$val;;
Y) y=$val;;
*)
esac
done
((result=x+y))
echo “X+Y=$result”
将脚本命名为 test.sh,并如下调用:
$ ./test.sh X=44 Y=100
它将输出 X+Y=144。参数存储在 “$@” 中,脚本使用 cut 命令进行解析。
16. 连接字符串
在 Bash 中连接字符串非常简单直接。
#!/bin/bash
string1=“Ubuntu”
string2=“Pit”
string=$string1$string2
echo “$string is a great resource for Linux beginners.”
17. 字符串截取
Bash 可以通过参数展开来截取子字符串。
#!/bin/bash
Str=“Learn Bash Commands from UbuntuPit”
subStr=${Str:0:20}
echo $subStr
该脚本会输出 “Learn Bash Commands”。参数展开的格式为 ${VAR_NAME:S:L},其中 S 是起始位置(从0开始),L 是要截取的长度。
18. 使用 cut 做截取
除了参数展开,也可以用 cut 命令来截取字符串,尤其适合按分隔符处理。
#!/bin/bash
Str=“Learn Bash Commands from UbuntuPit”
#subStr=${Str:0:20}
subStr=$(echo $Str| cut -d ‘ ’ -f 1-3)
echo $subStr
这里 -d ‘ ’ 指定空格为分隔符,-f 1-3 表示取第一到第三段,输出为 “Learn Bash Commands”。
19. 添加两个值
在 Shell 脚本中进行算术运算很简单。
#!/bin/bash
echo -n “Enter first number:”
read x
echo -n “Enter second number:”
read y
(( sum=x+y ))
echo “The result of addition=$sum”
使用双括号 (( )) 来进行计算。
20. 添加多个值
使用循环可以连续获取多个用户输入并进行累加。
#!/bin/bash
sum=0
for (( counter=1; counter<5; counter++ ))
do
echo -n “Enter Your Number:”
read n
(( sum+=n ))
done
printf “\n”
echo “Result is: $sum”
注意:如果不使用 (( )),+= 操作将会是字符串拼接而非数值相加。
21. Bash 中的函数
函数可以将常用代码块封装起来,提高代码复用率。
#!/bin/bash
function Add()
{
echo -n “Enter a Number: ”
read x
echo -n “Enter another Number: ”
read y
echo “Addition is: $(( x+y ))”
}
Add
这里定义了一个名为 Add 的函数来执行加法。之后每当需要加法功能时,只需调用 Add 函数即可。
22. 具有返回值的函数
函数可以通过标准输出“返回”数据。
#!/bin/bash
function Greet() {
str=“Hello $name, what brings you to UbuntuPit.com?”
echo $str
}
echo “-> what’s your name?”
read name
val=$(Greet)
echo -e “-> $val”
函数 Greet 中的 echo 输出被命令替换 $(...) 捕获,并赋值给了变量 val。
23. 从 Bash 脚本创建目录
Shell 脚本可以方便地调用系统命令,例如创建目录。
#!/bin/bash
echo -n “Enter directory name ->”
read newdir
cmd=“mkdir $newdir”
eval $cmd
脚本调用了 mkdir 命令。也可以使用反引号直接执行命令:
`mkdir $newdir`
24. 确认存在后创建目录
为了避免覆盖已有目录,可以先进行检查。
#!/bin/bash
echo -n “Enter directory name ->”
read dir
if [ -d “$dir” ]
then
echo “Directory exists”
else
`mkdir $dir`
echo “Directory created”
fi
[ -d “$dir” ] 用于判断 $dir 是否存在且是一个目录。
25. 读取文件
使用循环可以逐行读取文件内容。
#!/bin/bash
file=‘editors.txt’
while read line; do
echo $line
done < $file
假设 editors.txt 文件内容如下:
1. Vim
2. Emacs
3. ed
4. nano
5. Code
脚本将逐行输出这些内容。
26. 删除文件
下面的脚本会询问文件名,如果文件存在则将其删除。
#!/bin/bash
echo -n “Enter filename ->”
read name
rm -i $name
rm -i 中的 -i 选项会在删除前进行确认。输入 editors.txt 并在提示时按 y 确认,文件将被删除。
27. 附加到文件
使用重定向操作符 >> 可以向文件末尾追加内容。
#!/bin/bash
echo “Before appending the file”
cat editors.txt
echo “6. NotePad++” >> editors.txt
echo “After appending the file”
cat editors.txt
这个例子展示了如何直接在 Shell 脚本中调用常见的终端命令来完成文件操作。
28. 测试文件存在
此脚本用于检查指定的文件是否存在。
#!/bin/bash
filename=$1
if [ -f “$filename” ]; then
echo “File exists”
else
echo “File does not exist”
fi
文件名通过第一个命令行参数 $1 传递。[ -f “$filename” ] 用于检查路径是否为常规文件。
29. 从 Shell 脚本发送邮件
结合 mail 命令,可以从脚本中发送电子邮件。
#!/bin/bash
recipient=”admin@example.com”
subject=”Greetings”
message=”Welcome to UbuntuPit”
`mail -s $subject $recipient <<< $message`
此脚本会向收件人发送一封带有指定主题和内容的邮件。需要系统已配置好邮件发送服务。
30. 解析日期和时间
date 命令可以获取并格式化系统日期和时间。
#!/bin/bash
year=`date +%Y`
month=`date +%m`
day=`date +%d`
hour=`date +%H`
minute=`date +%M`
second=`date +%S`
echo `date`
echo “Current Date is: $day-$month-$year”
echo “Current Time is: $hour:$minute:$second”
运行此脚本以了解其功能。也可以直接在终端尝试运行 date 命令及其各种格式参数。
31. sleep 命令
sleep 命令可以让脚本暂停执行指定的秒数。
#!/bin/bash
echo “How long to wait?”
read time
sleep $time
echo “Waited for $time seconds!”
程序会在执行最后的 echo 命令前等待用户输入的秒数。
32. wait 命令
wait 命令用于等待某个后台进程结束。
#!/bin/bash
echo “Testing wait command”
sleep 5 &
pid=$!
kill $pid
wait $pid
echo $pid was terminated.
这个脚本启动了一个后台休眠进程,然后立即杀死它,并使用 wait 等待该进程真正结束。
33. 显示上次更新的文件
结合 ls、grep 和 awk 命令,可以找到当前目录中最近更新或创建的文件。
#!/bin/bash
ls -lrt | grep ^- | awk ‘END{print $NF}’
ls -lrt 以时间倒序列出文件,grep ^- 筛选出普通文件,awk 则打印出最后一行(即最新的文件)的最后一个字段(文件名)。
34. 添加批处理扩展
此脚本为指定目录下的所有文件添加统一的扩展名。
#!/bin/bash
dir=$1
for file in `ls $1/*`
do
mv $file $file.UP
done
注意:请先在测试目录中运行此脚本,不要直接在重要目录使用。运行时要提供目录路径作为参数,使用 . 代表当前目录。
35. 打印文件或目录的数量
使用 find 命令统计给定目录中的文件和文件夹数量。
#!/bin/bash
if [ -d “$@” ]; then
echo “Files found: $(find “$@” -type f | wc -l)”
echo “Folders found: $(find “$@” -type d | wc -l)”
else
echo “[ERROR] Please retry with another folder.”
exit 1
fi
脚本接收一个目录名作为参数。如果目录不存在或无权限访问,会提示错误。
36. 清理日志文件
这是一个实际的运维脚本示例,用于清空特定的日志文件。
#!/bin/bash
LOG_DIR=/var/log
cd $LOG_DIR
cat /dev/null > messages
cat /dev/null > wtmp
echo “Logs cleaned up.”
此脚本会清空 /var/log/messages 和 /var/log/wtmp 文件。请注意,需要 root 权限才能执行。
37. 使用 Bash 备份脚本
这是一个简单的备份脚本,用于打包过去 24 小时内修改过的文件。
#!/bin/bash
BACKUPFILE=backup-$(date +%m-%d-%Y)
archive=${1:-$BACKUPFILE}
find . -mtime -1 -type f -print0 | xargs -0 tar rvf “$archive.tar”
echo “Directory $PWD backed up in archive file \“$archive.tar.gz\”.”
exit 0
find . -mtime -1 查找一天内修改过的文件,tar 命令将其打包。备份成功后输出提示信息。这类自动化脚本是运维工作中不可或缺的一部分。
38. 检查你是否是 root 用户
通过比较用户 ID ($UID) 和 root 的用户 ID (0) 来判断当前用户身份。
#!/bin/bash
ROOT_UID=0
if [ “$UID” -eq “$ROOT_UID” ]
then
echo “You are root.”
else
echo “You are not root”
fi
exit 0
脚本的输出取决于运行它的用户。Root 用户的 $UID 为 0。
39. 从文件中删除重复行
使用 sort 和 uniq 命令可以轻松去除文件中的重复行。
#! /bin/sh
echo -n “Enter Filename-> ”
read filename
if [ -f “$filename” ]; then
sort $filename | uniq | tee sorted.txt
else
echo “No $filename in $pwd…try again”
fi
exit 0
脚本对文件内容进行排序,uniq 去除连续的重复行,tee 命令同时将结果输出到屏幕和 sorted.txt 文件,并保留原文件不变。
40. 系统维护
可以编写脚本自动执行系统更新和清理任务,替代手动操作。
#!/bin/bash
echo -e “\n$(date “+%d-%m-%Y — %T”) — Starting work\n”
apt-get update
apt-get -y upgrade
apt-get -y autoremove
apt-get autoclean
echo -e “\n$(date “+%T”) \t Script Terminated”
该脚本依次执行更新软件列表、升级已安装的包、自动移除不再需要的旧包、清理下载缓存等操作。需要使用 sudo 权限运行。
掌握这些基础的 Shell 脚本示例,已经能够应对许多日常的自动化任务。如果你想深入探讨更多复杂的运维与自动化场景,例如监控、持续集成或配置管理,欢迎在云栈社区与广大开发者一起交流学习。