linux shell 编程
接收用户参数
#!/bin/bash
echo "当前脚本名称为$0"
echo "总共有$#个参数,分别是$*"
echo "第 1 个参数为$1,第 5 个为$5"
$# 参数个数;$* 所有位置参数;$? 上一次命令执行返回值;$1 第一个位置参数
执行 sh example.sh one two three four five six, 输出:
当前脚本名称为 example.sh
总共有 6 个参数,分别是 one two three four five six
第 1 个参数为 one,第 5 个为 five
判断用户参数
Shell 脚本中的条件测试语法可以判断表达式是否成立,若条件成立则返回数字 0,否则便返回其他随机数值。例如,在创建文件之前,首先判断文件是否存在。
语法:[ Expression ] 注:括号两侧有空格
区别 shell 命令的返回值与输出值,返回值通过 $? 获取,而 var=
echo hhh是将输出结果赋值给 var 而不是返回值,管道命令也是如此。
条件测试语句分为
- 文件测试语句 (文件是否存在,权限是否满足等)
- 逻辑测试
- 整数比较
- 字符串比较

例如,终端执行 [ -d /dev ] && echo "is dir" , 则输出 “is dir”
整数比较

一个例子:
[ 100 -gt 99 ]
echo $?
输出 0
另一个较为综合的例子:
FreeMem=`free -m | grep Mem: | awk '{print $4}'`
[ $FreeMem -lt 1024 ] && echo "Insufficient Memory"
用于判断系统剩余内存是否小于 1024 M ,这条语句用到了管道命令 |和 awk 命令(处理文本)
流程控制
if 语句
单分支
DIR="tmp"
if [ ! -e $DIR ]
then mkdir -p $DIR
fi
双分支
DIR="tmp"
if [ ! -e $DIR ]
then mkdir -p $DIR
else echo "tmp exists!"
fi
多分支
if xxx
then xxx
elif xxx
then xxx
else
xxx
fi
for 语句
语法:
for var in value_list
do
xxx
done
给出一个批量建用户名的例子:
read -p "Enter The Users Password : " PASSWD # read 接收用户输入
for UNAME in `cat users.txt` # 反引号,当作命令执行,并返回结果
do
id $UNAME &> /dev/null
if [ $? -eq 0 ] # 判断上一条指令是否成功执行
then
echo "Already exists"
else
useradd $UNAME &> /dev/null
echo "$PASSWD" | passwd --stdin $UNAME &> /dev/null # 管道命令,将前一条命令的输出,作为后面命令的输入参数
if [ $? -eq 0 ]
then
echo "$UNAME , Create success"
else
echo "$UNAME , Create failure"
fi
fi
done
在脚本中使用 read 命令读取用户输入的密码值,然后赋值给 PASSWD 变量,并通过 -p 参数向用户显示一段提示信息,告诉用户正在输入的内容即将作为账户密码。在执行该脚本后,会自动使用从列表文件 users.txt 中获取到所有的用户
名称,然后逐一使用“id 用户名”命令查看用户的信息,并使用 $? 判断这条命令是否执行成功,也就是判断该用户是否已经存在。需要多说一句, /dev/null 是一个被称作 Linux 黑洞的文件,把输出信息重定向到这个文件等同于删除数据(类似于没有回收功能的垃圾箱),可以让用户的屏幕窗口保持简洁
注:shell 中的重定向
0表示标准输入
1表示标准输出
2表示标准错误输出
> 默认为标准输出重定向,与 1> 相同
2>&1 意思是把 标准错误输出 重定向到 标准输出.
&>file 意思是把 标准输出 和 标准错误输出 都重定向到文件 file 中
while 语句
语法:
while xxx
do xxx
done
例子
PRICE=$(expr $RANDOM % 1000) # expr 表达式求值,常用于数学运算
TIMES=0 # 等号两侧不能有空格
echo "商品实际价格为 0-999 之间,猜猜看是多少? "
while true
do
read -p "请输入您猜测的价格数目: " INT
let TIMES++ # let 用于数学计算
if [ $INT -eq $PRICE ] ; then
echo "恭喜您答对了,实际价格是 $PRICE"
echo "您总共猜测了 $TIMES 次"
exit 0
elif [ $INT -gt $PRICE ] ; then
echo "太高了! "
else
echo "太低了! "
fi
done
注:
- 等号两侧不能有空格
- 原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用
PRICE=$(expr $RANDOM % 1000)等价于PRICE=`expr $RANDOM % 1000`, 使用expr表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2- let 也可用于运算,
let s=(2+3)*4,let no++,let no+=10let 不需要空格隔开表达式的各个字符
常用指令
- 文本编辑指令
cat xxx more xxx head/tail -n 10 xxx # 最前或最后 10 行 cat anaconda-ks.cfg | tr [a-z] [A-Z] # tr 替换字符 wc -l/w/c xxx # wc 命令用于统计指定文本的行数、字数、字节数 stat xxx # 命令用于查看文件的具体存储信息和时间等信息 cut -d: -f1 /etc/passwd # 命令用于按“列”提取文本字符,格式为“ cut [参数] 文本” diff a.txt b.txt # 比较不同 tr -s 替换字符 -d 删除字符 sort 按行排序 -r 反向排序 uniq -c 统计每行词频 awk 动作 文件名 # 实施动作到每一行
shell 编程注意事项
- 变量引用必加 “$”
- echo 自动换行
- printf fmt args,… 类似 C 语言
- 区分某个命令的行为
- 对参数操作 echo/pringf
- 对输入流操作 cat/read
- 是否操作输出流 cat/echo
args == echo ==> stdout
args == printf ==> stdout
stdin == cat ==> stdout
stdin == read ==> args
shell 编程案例
- for 循环 1
for x in {1..100..2}
do
echo $x
done
- for 循环 2
for ((i=1; i<10; ++i))
do
echo $i
done
“(())” 内部可以不加 ‘$’
- 条件判断 1
read x
read y
if ((x<y))
then echo X is less than Y
elif ((x==y))
then echo X is equal to Y
else
echo X is greater than Y
fi
- 条件判断 2
read c
if [ $c = "Y" ] || [ $c = "y" ]
then echo YES
else
echo NO
fi
- 实现 eval 函数
read e
echo $e | bc -l | xargs printf "%.3f"
# 以上等价于
printf "%.3f\n" $(echo $(cat) | bc -l)
- 函数定义
# 定义
sum() {
echo $* | tr ' ' '+' | bc -l | xargs echo
}
# 调用
sum 1.544 4.7 8.7777