shell 脚本入门

shell 脚本入门

shell 是一种脚本语言,是用户与内核通信的一种方式。Linux上常见的Shell脚本解释器有bash、sh、csh、ksh等。一般来说 bash 是默认的 shell。

查看系统默认解释器:echo $SHELL

运行

运行前赋权

1
chmod +x hello.sh

作为解释器参数

运行解释器,脚本作为其参数。

1
/bin/bash hello.sh

这种方式无视解释器首行配置的解释器信息。

直接执行

1
2
cd path
./hello.sh

需要写成 ./ 的开头,如果不写,实际上系统会去 PATH 内寻找脚本,但 PATH 里只有 /bin,/usr/bin 之类的,所以启动会失败。

脚本头

1
#!/bin/bash

指定脚本的解释器

变量

变量名与等号间不能有空格,命名使用英文,下划线,数字,不能以数字开头。如 bar=hello。不能使用关键字,–help 查看关键字。

类型

  • 局部变量:在脚本或命令中定义,仅在当前shell中有效,其他shell启动的程序不能访问局部变量。

  • 环境变量:所有的程序,包括shell启动的程序,都能访问环境变量。必要的时候shell脚本也可以定义环境变量。

  • shell变量:shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量。

使用

定义的变量,使用时在前加 $ 表示引用。可以被重新定义。引用时也可以在变量外套花括号作为边界区分,避免被解释器把握为一个新的空变量。如 ${foo}bar$foobar

只读

对变量执行 readonly ,使其成为只读变量

1
2
3
4
foo=123
readonly foo
foo=456
#This variable is read only

删除

删除了再用就是空变量了。无法删除只读变量

1
unset foo

字符串

shell里的数据类型也就数字和字串。使用字符串时,单双引号都可以。需要注意的是,单引号字串中不能出现单独一个的单引号,用转义符也不行,但是可以成对使用表示字符串的拼接。

双引号里可以有变量,双引号里可以用转义字符

以拼接字符串作为例子

1
2
3
4
5
6
7
8
9
10
foo="example"
# 双引号
test1="this is an "$foo""
test2="this is an ${foo}"
# this is an example

# 单引号
test3='this is an '$foo''
test4='this is an ${foo}'
# this is an example, this is an ${foo}

字符串操作

  • 长度
  • 提取子串
  • 查找子串
1
2
3
4
5
6
7
8
9
10
string="string"
echo ${#string} # 6

echo ${string:1:3} # tri

echo `expr index "$string" tr` # 2
echo `expr index "$string" gt` # 2
echo `expr index "$string" s` # 1
# 用反引号``括起。搜索子串返回最先找到的那一个。
# 实际上还可以用正则、grep等等方式

数组

bash 只支持一维数组

1
2
3
4
5
array=(val0,val1)
echo $(array[1])
echo $(array[@]) # 输出所有元素
length=${#array[@]} #元素个数

命令

算符

一如既往,有算数运算符,关系运算符,布尔运算符,字符串运算符,文件测试运算符。

bash 不支持数学运算,一般还得用 expr,其中乘法 * 需要转义 \*

1
2
3
4
5
sum=`expr 2 + 4`	#反引号和空格需要留意
echo "sum=$sum" #sum=5

sum=2+4
echo $sum #输出2+4

关系运算符:-eq 相等,-ne 不等,-gt > ,-lt < ,-ge >= ,-le <=

布尔与逻辑算符:布尔( ! 非,-o 或, -a 与),逻辑( && 逻辑与, || 逻辑或),单括号 [ 中 -a 等价于双括号 [[ 中的 && 逻辑与。其他类似。

1
2
3
if [[ $a -eq $b || $a -lt $b ]]; then echo "yes"; fi	#yes
if true || true;then echo "YES"; else echo "NO"; fi #yes
if [ $a -eq $b -o $a -lt $b ]; then echo "yes"; fi #yes

echo & printf

echo一般是

1
2
3
echo "hello"
# 如果要输出命令结果
echo `date` #2020年 04月 ... (需要用反引号将命令引起)

echo 自动添加换行符,printf 则不会,需要自己添加 \n

1
2
printf "%-10s %-8s %-4s\n" 日期 星期 价格  
printf "%-10s %-8s %-4.2f\n" 20.3 五 66.1234

%s %c %d %f 都是格式替代符,%s 输出一个字符串,%d 整型输出,%c 输出一个字符,%f 输出实数,以小数形式输出。

%-10s 指一个宽度为 10 个字符(- 表示左对齐,没有则表示右对齐),任何字符都会被显示在 10 个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。

%-4.2f 指格式化为小数,其中 .2 指保留2位小数。

test

检验条件成立

1
2
3
if test 5 -eq 5;then echo "YES"; else echo "NO"; fi
if test -n "not empty";then echo "YES"; else echo "NO"; fi
if test -f /boot/System.map; then echo "YES"; else echo "NO"; fi

控制

if else

1
2
3
4
5
6
7
8
9
if condition
then
command
elif condition
then
command
else
command
fi

以 fi 结尾以示 if,同时,流程不可以为空,没有 else 的命令执行就不要写 else 分支

for

1
2
3
4
5
6
7
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done

while

1
2
3
4
while condition
do
command
done

until

1
2
3
4
until condition
do
command
done

case

1
2
3
4
5
6
7
8
case val in
case1)
command1
;;
case2)
command2
;;
esac

两个分号 ;; 表示 break

1
2
3
4
5
6
7
8
word="hello"

case "$word" in
"hello") echo "hi!"
;;
"bye") echo "bye!"
;;
esac

break continue

在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,两个命令来实现:break和continue。

break命令允许跳出所有循环(终止执行后面的所有循环)。continue不会跳出所有循环,仅仅跳出当前循环。

参考

Shell实验手册

作者

ivy

发布于

2020-04-13

更新于

2023-03-25

许可协议

CC BY-NC-SA 4.0

评论