目录
0主要学习内容
(1)掌握创建shell脚本的基本步骤;
(2)学会使用条件测试;
(3)掌握if条件结构与case选择结构;
(4)掌握for循环、while循环和until循环结构;
(5)学会shift命令的使用;
(6)学会shell脚本的调试;
1 Shell脚本
1.1 定义
如果有一系列你经常使用的Linux命令,你可以把它们存储在一个文件里,shell可以读取这个文件
并顺序执行其中的命令,这样的文件被称为脚本文件。
shell脚本按行进行解释。
1.2 Shell脚本的编写
(1)Shell脚本是纯文本文件,可以使用任何文本编辑器编写;
(2)Shell脚本通常是以.sh作为后缀名。
1.3 Shell脚本的执行
Chmod + x script_name
./script_name
Bash script_name
1.4 Shell脚本的格式
1.4.1 第一行
指定用哪个程序来编译和执行脚本。
例:#!/bin/bash;
#!/bin/sh;
#!/bin/csh。
1.4.2 可执行语句和shell控制结构
一个shell脚本通常由一组Linux命令、shell命令、控制结构和注释语句构成。
1.4.3 注释
以“#”开头,可独占一行,或跟在语句的后面,在脚本中多写注释语句是一个很好的编程习惯。
1.5 脚本举例
#!/bin/bash
# This is the first Bash shell program
# ScriptName: greetings.sh
echo
echo –e "Hello $LOGNAME, \c"
echo "it's nice talking to you."
echo "Your present working directory is:"
pwd # Show the name of present directory
echo
echo –e "The time is `date +%T`!. \nBye"
echo
Bash greetings.sh
Chmod + x greetings.sh
./greetings
1.6 echo命令
1.6.1 功能说明
用于显示文字。
1.6.2 语法
Echo [-ne] [字符串]或echo [--help] [--version]。
补充说明:echo会将输入的字符串送往标准输出。输出的字符串间以空白字符隔开,并在最后加上
换行号。
-n不进行换行
-e若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出\n换行\b空格...
1.7 常见参数
-n 不要在最后自动换行;
-e 若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出;
\a 发出警告声;
\b 删除前一个字符;
\c 最后不加上换行符号;
\f 换行但光标仍旧停留在原来的位置;
\n 换行且光标移至行首;
\r 光标移至行首,但不换行;
\t 插入tab;
\v与\f相同;
\\插入\字符;
\nnn插入nnn(八进制)所代表的ASCII字符;
--help 显示帮助;
--version 显示版本信息;
1.8 案例
#!/bin/bash
# This script is to test the usage of read
# Scriptname: ex4read.sh
echo "=== examples for testing read ==="
echo -e "What is your name? \c"
read name
echo "Hello $name"
echo
echo -n "Where do you work? "
read
echo "I guess $REPLY keeps you busy!"
echo
read -p "Enter your job title: "#自动读给REPLY
echo "I thought you might be an $REPLY."
echo
echo "=== End of the script ==="
1.8.1 read命令
read variable #读取变量给variable
read x y #可同时读取多个变量
read #自动读给REPLY
read –p “Please input: ” #自动读给REPLY
[-p]用法:read –p “string” var1 var2…varn,
#!/bin/bash
TIP="Input your information:
Read -p "$TIP" name sex
echo $name
echo $sex
2条件测试
(1)条件测试可以根据某个特定条件是否满足,来选择执行相应的任务。
(2)Bash中允许测试两种类型的条件:
命令成功或失败,表达式为真或假
(3)任何一种测试中,都要有退出状态(返回值),退出状态为0表示命令成功或表达式为真,非
0则表示命令失败或表达式为假。
(4)状态变量$?中保存命令退出状态的值。
grep $USER /etc/passwd
echo $?
grep hello /etc/passwd
Echo $?
2.1 测试表达式的值
(1)表达式测试包括字符串测试、整数测试和文件测试;
(2)内置测试命令test
通常用test命令来测试表达式的值,例:
x=5;y=10
test $x -gt$y
echo $?
test命令可以用方括号来代替,例:
x=5;y=10
[ $x -gt $y]
echo $?
3 字符串测试
操作符两边必须留空格!
| [ -z str ] | 如果字符串 str 长度为 0,返回真 |
| [ -n str ] | 如果字符串 str 长度不为 0,返回真 |
| [ str1 = str2 ] | 两字符串相等 |
| [ str1 != str2 ] | 两字符串不等 |
name=Tom;[ -z $name ];echo $?
name2=Andy;[ $name = $name2 ];echo $?
4 整数测试
整数测试,即比较大小,操作符两边必须留空格!
| [ int1 -eq int2 ] | int1 等于 int2 |
| [ int1 -ne int2 ] | int1 不等于 int2 |
| [ int1 -gt int2 ] | int1 大于 int2 |
| [ int1 -ge int2 ] | int1 大于或等于 int2 |
| [ int1 -lt int2 ] | int1 小于 int2 |
| [ int1 -le int2 ] | int1 小于或等于 int2 |
x=1;[ $x -eq 1 ];echo $? #正确示例
x=a;[ $x -eq 1];echo $? #错误示例
整数测试也可以使用let命令或双圆括号,只能用于整数测试!
相应的操作符为:==、!=、>、>=、<、<=;
例:x=1;let "$x == 1";echo $?
x=1;(($x+1>= 2 ));echo $?
两种测试方法的区别:
(1)使用的操作符不同;
(2)let和双圆括号中可以使用算术表达式,而中括号不能;
(3)let和双圆括号中,操作符两边可以不留空格。
5 逻辑测试
| [ expr1 -a expr2 ] | 逻辑与,都为真时,结果为真 |
| [ expr1 -o expr2 ] | 逻辑或,有一个为真时,结果为真 |
| [ ! expr ] | 逻辑非 |
x=1;name=Tom;
[$x -eq 1–a–n $name];echo $?
千万不能随便添加括号;
[($x -eq 1) –a( –n $name)];echo $? #错误示例
5.1 可以使用模式的逻辑测试
| [[ pattern1 && pattern2 ]] | 逻辑与 |
| [[ pattern1 || pattern2 ]] | 逻辑或 |
| [[ ! pattern ]] | 逻辑非 |
x=1;name=Tom;
[[$x -eq 1 && $name =To? ]];echo $?
6 文件测试
文件测试:主要测试文件是否存在,文件属性,访问权限等,常见的文件测试操作符主要有:
| -f fname | fname 存在且是普通文件时,返回真 ( 即返回 0 ) |
| -L fname | fname 存在且是链接文件时,返回真 |
| -d fname | fname 存在且是一个目录时,返回真 |
| -e fname | fname(文件或目录)存在时,返回真 |
| -s fname | fname 存在且大小大于 0 时,返回真 |
| -r fname | fname(文件或目录)存在且可读时,返回真 |
| -w fname | fname(文件或目录)存在且可写时,返回真 |
| -x fname | fname(文件或目录)存在且可执行时,返回真 |
更多文件测试符请参考test的在线帮助,例:
#!/bin/bash
[-f/home/ygl123.sh]
Echo $?
[-L/home/ygl123.sh]
Echo $?
[-d/home/ygl123.sh]
Echo $?
[-e/home/ygl123.sh]
Echo $?
[-s/home/ygl123.sh]
7 if条件语句
7.1 语法结构
if expr1 # 如果expr1 为真(返回值为0)
then # 那么
commands1 # 执行语句块 commands1
elif expr2 # 若expr1 不真,而expr2 为真
then # 那么
commands2 # 执行语句块 commands2
...... # 可以有多个 elif 语句
else # else 最多只能有一个
commands4 # 执行语句块 commands4
fi # if语句必须以单词fi终止
需注意以下几点:
(1)elif可以有任意多个(0个或多个);
(2)else最多只能有一个(0个或1个);
(3)if语句必须以fi表示结束;
(4)expr通常为条件测试表达式;也可以是多个命令,以最后一个命令的退出状态为条件值;
(5)commands为可执行语句块,如果为空,需使用shell提供的空命令“:”,即冒号。该命令不做
任何事情,只返回一个退出状态0;
(6)if语句可以嵌套使用。
ex4if.sh
#!/bin/bash
# scriptname: ex4if.sh
#
echo -n "Please input x,y: "
read x y
echo "x=$x, y=$y"
if (( x > y )); then
echo "x is larger than y"
elif (( x == y)); then
echo "x is equal to y"
else
echo "x is less than y"
fi
chkperm.sh
#!/bin/bash
# Using the old style test command: [ ]
# filename: perm_check.sh
#
file=testing
if [ -d $file ]
then
echo "$file is a directory"
elif [ -f $file ]
then
if [ -r $file -a -w $file -a -x $file ]
then # nested if command
echo "You have read,write,and execute permission on $file."
fi
else
echo "$file is neither a file nor a directory. "
fi
8 shell变量
$0 Shell本身的文件名
$1~$n 添加到Shell的各参数值,$1是第1参数、$2是第2参数…
$$Shell 本身的PID(ProcessID)
$? 最后运行的命令的结束代码(返回值)
$* 所有参数列表。如“$*”用「“」括起来的情况、以"$1$2…$n"的形式输出所有数。
$@ 所有参数列表。如"$@"用「"」括起来的情况、以"$1""$2"…"$n"的形式输出所有参数。
$# 添加到Shell的参数个数。
9 case选择语句
9.1 语法结构
case expr in # expr为表达式,关键词in不要忘!
pattern1) # 若expr与pattern1匹配,注意括号
commands1 # 执行语句块commands1
;; # 跳出case结构
pattern2) # 若expr与pattern2匹配
commands2 # 执行语句块commands2
;; # 跳出case结构
... ... # 可以有任意多个模式匹配
*) # 若expr 与上面的模式都不匹配
commands # 执行语句块commands
;; # 跳出case结构
esac # case语句必须以esac终止
需注意以下几点:
(1)表达式expr按顺序匹配每个模式,一旦有一个模式匹配成功,则执行该模式后面的所有命
令,然后退出case;
(2)如果expr没有找到匹配的模式,则执行缺省值“*)”后面的命令块(类似于if中的else);“*)”可以
不出现;
(3)所给的匹配模式pattern中可以含有通配符和“|”;
(4)每个命令块的最后必须有一个双分号,可以独占一行,或放在最后一个命令的后面;
(5)case语句举例:yes_no.sh,具体文件如下:
#!/bin/bash
# test case
# scriptname: yes_no.sh
#
echo -n "Do you wish to proceed [y/n]: "
read ans
case $ans in
y|Y|yes|Yes)
echo "yes is selected"
;;
n|N|no|No)
echo "no is selected"
;;
*)
echo "`basename $0`: Unknown response"
exit 1
;;
esac
用法示例:
$ basename /usr/bin/sort 输出"sort"。
$ basename ./include/stdio.h .h 输出"stdio"。
basename命令格式:
basename [pathname] [suffix]
basename [string] [suffix]
$basename/tmp/test/file.txt
file.txt
$basename/tmp/test/file.txt.txt
suffix为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉。
示例:
$ basename /tmp/test/file.txt
file.txt
$ basename /tmp/test/file.txt .txt
file
10 for循环语句
10.1 语法结构
for variable in list
# 每一次循环,依次把列表 list 中的一个值赋给循环变量
do # 循环开始的标志
commands # 循环变量每取一次值,循环体就执行一遍
done # 循环结束的标志
需注意以下几点:
(1)列表list可以是命令替换、变量名替换、字符串和文件名列表(可包含通配符);
(2)for循环执行的次数取决于列表list中单词的个数;
(3)for循环体中一般要出现循环变量,但也可以不出现。
10.2 for循环执行过程
执行第一轮循环时,将list中的第一个词赋给循环变量,并把该词从list中删除,然后进入循环体,
执行do和done之间的命令。下一次进入循环体时,则将第二个词赋给循环变量,并把该词从list中
删除,再往后的循环也以此类推。当list中的词全部被移走后,循环就结束了。
For loop.sh,my backup.sh
位置参量的使用:$*与$@,greet.sh
可以省略inlist,此时使用位置参量,
permx.sh idcheck.sh greet.sh yes_no.sh
permx.sh *.sh
forloop.sh
#!/bin/bash
#Script name:for loop.sh
For name in Tom Dick Harry Joe
do
echo "Hi $name"
done
forloop2.sh
#!/bin/bash
#Scriptname:forloop2.sh
For name in`cat namelist`
do
echo "Hi $name"
done
cat主要有三大功能:
(1)一次显示整个文件。$catfilename
(2)从键盘创建一个文件。$cat>filename,只能创建新文件,不能编辑已有文件.
(3)将几个文件合并为一个文件:$catfile1file2>file
#mybackup.sh
#!/bin/bash
backup_dir=backup
mkdir $backup_dir
for file in *.sh
do
if [ -f $file ]
then
cp $file $backup_dir/${file}.bak
echo "$file is backed up in $backup_dir"
fi
done
#greet.sh
#!/bin/bash
echo "== using \$* =="
for name in $*
echo Hi $name
done
echo "== using \$@ =="
for name in $@ # same as for name in $*
do
echo Hi $name
done
echo '== using "$*" =='
for name in "$*"
do
echo Hi $name
done
echo '== using "$@" =='
for name in "$@"
do
echo Hi $name
done
#!/bin/bash
for file in *.sh
do
if [[ -f $file && ! -x $file ]]
then
chmod +x $file
echo " == $file now has execute permission"
fi
done
11 while循环语句
11.1 语法结构
while expr # 执行expr
do # 若expr的退出状态为0,进入循环,否则退出while
commands # 循环体
done # 循环结束标志,返回循环顶部
11.2 执行过程
先执行expr,如果其退出状态为0,就执行循环体。执行到关键字done后,回到循环的顶部,while
命令再次检查expr的退出状态。以此类推,循环将一直继续下去,直到expr的退出状态非0为止。
12 until循环语句
12.1 语法结构
until expr # 执行expr
do # 若expr的退出状态非0,进入循环,否则退出until
commands # 循环体
done # 循环结束标志,返回循环顶部
12.2 执行过程
与while循环类似,只是当expr退出状态非0时才执行循环体,直到expr为0时退出循环。
13 break和continue
13.1 break[n]
(1)用于强行退出当前循环;
(2)如果是嵌套循环,则break命令后面可以跟一数字n,表示退出第n重循环(最里面的为第一
重循环)。
13.2 continue [n]
(1)用于忽略本次循环的剩余部分,回到循环的顶部,继续下一次循环;
(2)如果是嵌套循环,continue命令后面也可跟一数字n,表示回到第n重循环的顶部,
例:months.sh。
14 exit和sleep
14.1 exit命令
exitn,exit命令用于退出脚本或当前进程。n是一个从0到255的整数,0表示成功退出,非零表示遇
到某种失败而非正常退出。该整数被保存在状态变量$?中。
14.2 sleep命令
sleepn,暂停n秒钟。
15 select循环与菜单
15.1 语法结构
select variable in list
do # 循环开始的标志
commands # 循环变量每取一次值,循环体就执行一遍
done # 循环结束的标志
15.2 注意事项
(1)select循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示PS3提
示符,等待用户输入;
(2)用户输入菜单列表中的某个数字,执行相应的命令;
(3)用户输入被保存在内置变量REPLY中。
例:runit.sh:
#!/bin/bash
PS3="Select a program to execute: "
select program in 'ls -F' pwd date
do
$program
done
16 select与case
select是个无限循环,因此要记住用break命令退出循环,或用exit命令终止脚本。也可以按ctrl+c退
出循环。
(1)select经常和case联合使用。例:goodboy.sh
#!/bin/bash
# Scriptname: goodboys.sh
PS3="Please choose one of the three boys : "
select choice in tom dan guy
do
case $choice in
tom)
echo Tom is a cool dude!
break;; # break out of the select loop
dan | guy )
echo Dan and Guy are both wonderful.
break;;
*)
echo "$REPLY is not one of your choices"
echo "Try again."
;;
esac
done
(2)与for循环类似,可以省略inlist,此时使用位置参量。
17 循环控制shift命令
17.1 shift [n]
(1)用于将参量列表list左移指定次数,缺省为左移一次;
(2)参量列表list一旦被移动,最左端的那个参数就从列表中删除。while循环遍历位置参量列表
时,常用到shift。
例:./doit.sh a b c d e f g h
./shft.sh a b c d e f g h
#doit.sh
#!/bin/bash
while (( $# > 0 )) # or [ $# -gt 0 ]
do
echo $*
shift
done
18 随机数和expr命令
生成随机数的特殊变量,例:
echo $RANDOM 范围是:[0,32767]
expr:通用的表达式计算命令,表达式中参数与操作符必须以空格分开,表达式中的运算可以是算
术运算,比较运算,字符串运算和逻辑运算。
例:expr 5 % 3
Expr 5 \* 3 #乘法符号必须被转义
19 脚本调试
19.1 h–x脚本名
该选项可以使用户跟踪脚本的执行,此时shell对脚本中每条命令的处理过程为:先执行替换,然后
显示,再执行它。
shell显示脚本中的 执行时,会在行首添加一个加号“+”。
19.2 sh–v脚本名
在执行脚本之前,按输入的原样打印脚本中的各行,打印一行执行一行。
19.3 sh–n脚本名
对脚本进行语法检查,但不执行脚本。如果存在语法错误,shell会报错,如果没有错误,则不显示
任何内容。
20 小结
20.1 变量
20.1.1 局部变量、环境变量
(export、declare-x)
20.1.2 只读变量、整型变量
例:declare-ix;x="hello";echo$x,输出:0
20.1.3 位置参量
$0,$1,...,$*,$@,$#,$$,$?
20.1.4 变量的间接引用(eval,${!str})
例:name="hello";x="name";echo${!x},输出hello
20.1.5 命令替换
(`cmd`、$(cmd))
20.1.6 整数运算
declare定义的整型变量可以直接进行运算,否则需用let命令或$[...]、$((...))进行整数运算。
20.2 条件测试
20.2.1 符串测试
字符串测试,操作符两边必须留空格!
| [ -z string ] | 如果字符串string长度为0,返回真 |
| [ -n string ] | 如果字符串string长度不为0,返回真 |
| [ str1 = str2 ] | 两字符串相等(也可以使用 == ) |
| [ str1 != str2 ] | 两字符串不等 |
注意:如果使用双方括号,可以使用通配符进行模式匹配。
| [[ str1 = str2 ]] | 两字符串相等(也可以使用 == ) |
| [[ str1 != str2 ]] | 两字符串不等 |
| [[ str1 > str2 ]] | str1大于str2,按ASCII码比较 |
| [[ str1 < str2 ]] | str1小于str2,按ASCII码比较 |
例:name=Tom;[[$name>Tom]];echo$?
20.2.2 整数测试
整数测试,注意这两种方法的区别如下:
| [ int1 -eq int2 ] | int1 等于 int2 |
| [ int1 -ne int2 ] | int1 不等于 int2 |
| [ int1 -gt int2 ] | int1 大于 int2 |
| [ int1 -ge int2 ] | int1 大于或等于 int2 |
| [ int1 -lt int2 ] | int1 小于 int2 |
| [ int1 -le int2 ] | int1 小于或等于 int2 |
| [[int1 == int2]] | int1 等于 int2 |
| [[int1 != int2]] | int1 不等于 int2 |
| [[int1 > int2]] | int1 大于 int2 |
| [[int1 >= int2]] | int1 大于或等于 int2 |
| [[int1 < int2]] | int1 小于 int2 |
| [[int1 <= int2]] | int1 小于或等于 int2 |
20.2.3 逻辑测试
| [ expr1 -a expr2 ] | 逻辑与,都为真时,结果为真 |
| [ expr1 -o expr2 ] | 逻辑或,有一个为真时,结果为真 |
| [ ! expr ] | 逻辑非 |
如果使用双方括号,可以使用通配符进行模式匹配。
| [[ pattern1 && pattern2 ]] | 逻辑与 |
| [[ pattern1 || pattern2 ]] | 逻辑或 |
| [[ ! pattern ]] | 逻辑非 |
20.2.4 文件测试
| -f fname | fname 存在且是普通文件时,返回真 ( 即返回 0 ) |
| -L fname | fname 存在且是链接文件时,返回真 |
| -d fname | fname 存在且是一个目录时,返回真 |
| -e fname | fname(文件或目录)存在时,返回真 |
| -s fname | fname 存在且大小大于 0 时,返回真 |
| -r fname | fname(文件或目录)存在且可读时,返回真 |
| -w fname | fname(文件或目录)存在且可写时,返回真 |
| -x fname | fname(文件或目录)存在且可执行时,返回真 |
20.3 控制结构
(1)if条件语句;
(2)case选择语句;
(3)for循环语句;
(4)while循环语句;
(5)until循环语句;
(6)break、continue、sleep命令;
(7)select循环与菜单;
(8)shift命令;
(9)各种括号的作用,${...},$(...),$[...],$((...)),[...],[[...]],((...))。
20.4 函数
(1)和其它编程语言一样,Bash也可以定义函数。
(2)一个函数就是一个子程序,用于完成特定的任务,当有重复代码,或者一个任务只需要很少
的修改就被重复几次执行时,这时你应考虑使用函数。
(3)函数的一般格式如下:
function function_name {
commands
}
function_name () {
commands
}
(4)函数例子:
#!/bin/bash
fun1 () {
echo "This is a function"
echo "Now exiting fun1."
}
fun2 ()
{
echo "This is fun2."
echo "Now exiting fun2."
}
20.4.1 函数的调用
(1)只需输入函数名即可调用该函数;
(2)函数必须在调用之前定义:,例:
#!/bin/bash
fun2 ()
{
echo "This is fun2."
echo "Now exiting fun2."
}
fun2 # 调用函数 fun2
例:ex4fun2.sh、ex4fun3.sh。
#ex4fun2.sh
#!/bin/bash
JUST_A_SECOND=1
fun ()
{
i=0
REPEATS=5
echo "And now the fun really begins."
sleep $JUST_A_SECOND
while [ $i -lt $REPEATS ]
do
echo "----------FUNCTIONS---------->"
echo "<------------ARE-------------"
echo "<------------FUN------------>"
echo
let "i+=1"
done
}
# Now, call the functions.
fun
exit 0
#ex4fun3.sh
f1 () {
echo "Calling function \"f2\" from within function \"f1\"."
f2
}
f2 () {
echo "Function \"f2\"."
}
f1
20.4.2 向函数传递参数
例:ex4fun4.sh
20.4.3 函数与命令行参数
例:ex4fun5.sh
20.4. 4 return与exit
例:ex4fun6.sh
20.4.5 补充几种特殊的替换结构
${var:string},${var:+string},${var:=string},${var:?string}
①${var:-string}和${var:=string}:若变量var为空,则用在命令行中用string来替换${var:-string},否
则变量var不为空时,则用变量var的值来替换${var:-string};对于${var:=string}的替换规则
和${var:-string}是一样的,所不同之处是${var:=string}若var为空时,用string替换${var:=string}的
同时,把string赋给变量var:${var:=string}很常用的一种用法是,判断某个变量是否赋值,没有的
话则给它赋上一个默认值。
②${var:+string}的替换规则和上面的相反,即只有当var不是空的时候才替换成string,若var为空
时则不替换或者说是替换成变量var的值,即空值。(因为变量var此时为空,所以这两种说法是等价
的)
③${var:?string}替换规则为:若变量var不为空,则用变量var的值来替换${var:?string};若变量
var为空,则把string输出到标准错误中,并从脚本中退出。我们可利用此特性来检查是否设置了变
量的值。
补充扩展:在上面这五种替换结构中string不一定是常值的,可用另外一个变量的值或是一种命
令的输出。
本文详细介绍了Shell脚本的基础知识,包括脚本的编写、执行、格式等内容,并深入讲解了条件测试、循环控制结构等核心概念。此外还提供了丰富的实例帮助理解。
1万+

被折叠的 条评论
为什么被折叠?



