Linux程序设计(2) Shell Programming
2023-08-18 16:12:32 # NJU # Linux程序设计

1. What is Shell?

  • Shell: A command interpreter and programming environment
  • 用户和操作系统之间的接口
  • 作为核外程序而存在
用户和操作系统之间的接口 作为核外程序而存在
image-20230306124606364 image-20230306124706409

1.1 各种不同的Shell

image-20230306124806455

1.2 Shell 的双重角色

  • 命令解释程序
    • Linux的开机启动过程;进程树
    • Shell的工作步骤:打印提示符;得到命令行;解析命令;查找文件;准备参数;执行命令
  • 独立的程序设计语言解释器
    • KISS (Keep It Small and Stupid)
    • Reusable tools
    • Redirection and pipe

2. 脚本

2.1 使用命令行

脚本是能在命令行直接输入的,但仅会执行一次

image-20230313132013304

2.2 编写脚本文件

脚本文件

  • 注释
  • 退出码(exit code)

image-20230313132145225

2.3 执行脚本文件

方法一:

1
sh script_file 

方法二:

1
2
chmod +x script_file(chown, chgrp optionally)
./script_file

方法三:

1
2
source script_file
. script_file

方法一二原理相同:新启bash进程执行脚本

方法三使用当前bash进程执行脚本

2.4 用户环境

.bash_profile.bash_logout.bashrc files

  • .bash_profile: 用户登录时被读取,其中包含的命令被bash执行
  • .bashrc: 启动一个新的shell时读取并执行
  • .bash_logout: 登录退出时读取执行

Alias

  • alias/unaliascommand

环境变量

  • export command

  • export, env & set command

3. 变量

3.1 用户变量

  • 用户变量:

    • 用户在shell脚本里定义的变量
  • 变量的赋值和使用

    • var=value

    • echo $var

  • read命令

    • 用法:read varread

    • REPLY variable

  • 引号的用法

    • 双引号,单引号

    • 转义符 \

=两侧不能加空格

变量没有类型,或者可以认为是字符串

Read用法

1
2
3
4
5
#! /bin/bash
echo -n "Enter your name: " # 参数-n的作用是不换行,echo默认是换行
read name #从键盘输入
echo "hello $name, welcome to my program"
exit 0 #退出shell程序。
1
2
3
4
5
read -p "Enter your name:" name   #-p参数,允许在read命令行中直接指定一个提示

read -p "Enter a number:" number
echo $number
exit 0
1
2
3
4
5
6
7
8
9
#! /bin/bash
# 5s内输入
if read -t 5 -p "please enter your name:" name
then
echo "hello $name, welcome to my script"
else
echo "sorry, too slow"
fi
exit 0
1
2
3
4
5
6
7
8
9
10
11
12
#! /bin/bash
# 只读取一个字符
read -n1 -p "Do you want to continue [Y/N] ?" answer
case $answer in
Y|y)
echo "fine, continue";;
N|n)
echo "ok, good bye";;
*)
echo "error choice";;
esac
exit 0
1
2
3
4
5
#! /bin/bash
# 不显示输入
read -s -p "Enter your password: " pass
echo "your password is $pass"
exit 0
1
2
3
4
5
6
7
8
9
#! /bin/bash
count=1
cat viewFile.sh| while read line
do
echo "Scount:$line"
count=$(($count + 1))
done
echo "Total Count:$count"
exit 0

引号的用法

单引号内的所有字符都保持它本身字符的意思,而不会被bash进行解释,例如,\$就是\$本身而不再是bash的变量引用符;\就是\本身而不再是bash的转义字符。

除了$、``(不是单引号)和 外,双引号内的所有字符将保持字符本身的含义而不被bash解释

3.2 环境变量

Shell环境提供的变量。通常使用大写字母做名字

image-20230313143814653

3.3 参数变量和内部变量

调用脚本程序时如果带有参数,对应的参数和额外产生的一些变量。

image-20230313143945908

4. 语句

4.1 条件测试

退出码

test命令:test expression[ expression ]

test命令支持的条件测试

  1. 字符串比较
  2. 算术比较
  3. 与文件有关的条件测试
  4. 逻辑操作

字符串比较

image-20230313144119488

算术比较

image-20230313144151627

与文件有关的条件测试

image-20230412230824083

逻辑操作

image-20230412231419320

4.2 if语句

1
2
3
4
5
6
7
8
9
10
if [expression]
then
statements
elif [expression]
then
statements
elif...
else
statements
fi
  • 紧凑模式:使用 ; 分割
1
2
3
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi

4.3 case语句

  • 双分号
1
2
3
4
5
case str in
str1 | str2) statements;;
str3 | str4) statements;;
*) statements;
esac
1
2
3
4
5
6
7
8
9
#!/bin/sh
echo "Is this morning? Please answer yes or no."
read answer
case "$answer" in
yes | y | Yes | YES) echo "Good morning!";;
no | n | No | NO) echo "Good afternoon!";;
*) echo "Sorry, answer not recognized.";;
esac
exit 0

4.4 for语句

  • 适用于对一系列字符串循环处理
1
2
3
4
for var in list
do
statements
done
1
2
3
4
5
#!/bin/sh
for file in $(ls f*.sh); do
lpr $file
done
exit 0

4.5 while语句

1
2
3
4
while [expression]
do
statements
done
1
2
3
4
5
6
7
8
9
10
quit=n
while [ "$quit" != "y"]; do
read menu_choice
case "$menu_choice" in
a) do_something;;
b) do_anotherthing;;
q|Q) quit=y;;
*) echo "Sorry, choice not recognized.";;
esac
done
1
2
3
4
5
6
7
8
a=0
while [ "$a" -le "$LIMIT" ]; do
a=$(($a+1))
if [ "$a" gt 2 ]; then
break # Skip entire rest of loop.
fi
echo -n "$a"
done
  • $(())整数运算,否则会看作字符串

  • 不推荐使用 until

4.6 select语句

生成菜单列表

1
2
3
4
5
6
7
8
9
10
#!/bin/sh
clear
select item in Continue Finish
do
case "$item" in
Continue) ;;
Finish) break ;;
*) echo "Wrong choice! Please select again!" ;;
esac
done

image-20230412233820317

4.7 命令表和语句块

命令表

命令组合

  • 分号串联:command1 ; command2 ; …

  • AND命令表(&&): 前面成功才会执行后面的命令

  • OR命令表(||): 前面失败才会执行, 可用作备用命令

  • {statement1; statement2 ; … ;} 会看做一个命令

语句块

1
2
3
4
5
6
7
{
statement1
statement2
...
}

{statement1; statement2 ; ... ;}

4.8 函数

定义时不带参数

1
2
3
4
func()
{
statements
}
  • 局部变量: local关键字
  • 函数的调用: func para1 para2 …
  • 返回值: return

例子

image-20230412235748650

image-20230412235756115

5. 其他

5.1 杂项命令

  • break: 从for/while/until循环退出
  • continue: 跳到下一个循环继续执行
  • exit n: 以退出码”n”退出脚本运行
  • return: 函数返回
  • export: 将变量导出到shell,使之成为shell的环境变量
  • set: 为shell设置参数变量
  • unset: 从环境中删除变量或函数
  • trap: 指定在收到操作系统信号后执行的动作
  • “:”(冒号命令): 空命令
  • “.”(句点命令)或source: 在当前shell中执行命令

5.2 捕获命令输出

  • $(command) 或 `command`

  • $PWD 与 $(pwd)

5.3 算术扩展

image-20230818160959917

5.4 参数扩展

问题:批处理 1_tmp, 2_tmp, …

方法:

1
2
3
4
5
6
7
#! /bin/sh
i=1
while [ "$i" -ne 10 ]; do
touch "${i}_tmp"
i=$(($i+1))
done
exit 0

参数扩展更复杂的形式

image-20230413000143071

5.5 即时文档

  • 在shell脚本中向一条命令传送输入数据

  • 例如: 输入 !CATINPUT! 才会停止

1
2
3
4
5
#!/bin/bash
cat >> file.txt << !CATINPUT!

Hello, this is a here document.
!CATINPUT!