【鸟哥的linux私房菜-学习笔记】Shell script基础

时间:2022-07-12 08:46:29

第一支 script 的撰写与运行

注意事项:

命令的运行是从上而下、从左而右的分析与运行;
命令的下达就如同第五章内提到的: 命令、选项与参数间的多个空白都会被忽略掉;
空白行也将被忽略掉,并且 [tab] 按键所推开的空白同样视为空白键;
如果读取到一个 Enter 符号 (CR) ,就尝试开始运行该行 (或该串) 命令;
至於如果一行的内容太多,则可以使用『 \[Enter] 』来延伸至下一行;
『 # 』可做为注解!任何加在 # 后面的数据将全部被视为注解文字而被忽略!

撰写第一支 script

[root@www ~]# mkdir scripts; cd scripts
[root@www scripts]# vi sh01.sh
#!/bin/bash
# Program:
# This program shows "Hello World!" in your screen.
# History:
# 2015/11/03 Jiange First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "Hello World! \a \n"
exit 0

第一行 #!/bin/bash 在宣告这个 script 使用的 shell 名称,如果没有配置好这一行, 那么该程序很可能会无法运行,因为系统可能无法判断该程序需要使用什么 shell 来运行。

主要环境变量的宣告:
建议务必要将一些重要的环境变量配置好,如PATH 与 LANG 。如此一来,则可让我们这支程序在进行时,可以直接下达一些外部命令,而不必写绝对路径。

运行

chmod a+x sh01.sh; ./sh01.sh

或者

sh sh01.sh

良好的 script 撰写习惯

在每个 script 的档头处记录好:

script 的功能;
script 的版本资讯;
script 的作者与联络方式;
script 的版权宣告方式;
script 的 History (历史纪录);
script 内较特殊的命令,使用『绝对路径』的方式来下达;
script 运行时需要的环境变量预先宣告与配置。

对谈式脚本:变量内容由使用者决定

[root@www scripts]# vi sh02.sh
#!/bin/bash
# Program:
# User inputs his first name and last name. Program shows his full name.
# History:
# 2005/08/23 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

read -p "Please input your first name: " firstname # 提示使用者输入
read -p "Please input your last name: " lastname # 提示使用者输入
echo -e "\nYour full name is: $firstname $lastname" # 结果由萤幕输出

随日期变化:利用 date 进行文件的创建

[root@www scripts]# vi sh03.sh
#!/bin/bash
# Program:
# Program creates three files, which named by user's input
# and date command.
# History:
# 2005/08/23 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

# 1. 让使用者输入文件名称,并取得 fileuser 这个变量;
echo -e "I will use 'touch' command to create 3 files." # 纯粹显示资讯
read -p "Please input your filename: " fileuser # 提示使用者输入

# 2. 为了避免使用者随意按 Enter ,利用变量功能分析档名是否有配置?
filename=${fileuser:-"filename"} # 开始判断有否配置档名

# 3. 开始利用 date 命令来取得所需要的档名了;
date1=$(date --date='2 days ago' +%Y%m%d) # 前两天的日期
date2=$(date --date='1 days ago' +%Y%m%d) # 前一天的日期
date3=$(date +%Y%m%d) # 今天的日期
file1=${filename}${date1} # 底下三行在配置档名
file2=${filename}${date2}
file3=${filename}${date3}

# 4. 将档名创建吧!
touch "$file1" # 底下三行在创建文件
touch "$file2"
touch "$file3"

数值运算:简单的加减乘除

[root@www scripts]# vi sh04.sh
#!/bin/bash
# Program:
# User inputs 2 integer numbers; program will cross these two numbers.
# History:
# 2005/08/23 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "You SHOULD input 2 numbers, I will cross them! \n"
read -p "first number: " firstnu
read -p "second number: " secnu
total=$(($firstnu*$secnu))
echo -e "\nThe result of $firstnu x $secnu is ==> $total"

在数值的运算上,我们可以使用『 declare -i total=$firstnu*$secnu 』 也可以使用上面的方式来进行:var=$((运算内容))。

script 的运行方式差异 (source, sh script, ./script)

利用直接运行的方式来运行 script:

当使用直接命令下达 (不论是绝对路径/相对路径还是 $PATH 内),或者是利用 bash (或 sh) 来下达脚本时, 该 script 都会使用一个新的 bash 环境来运行脚本内的命令。也就是说,使用者种运行方式时, 其实 script 是在子程序的 bash 内运行的。所以:『当子程序完成后,在子程序内的各项变量或动作将会结束而不会传回到父程序中』!

利用 source 来运行脚本:在父程序中运行

利用 test 命令的测试功能

[root@www ~]# test -e /dmtsai && echo "exist" || echo "Not exist"

如果不存在则显示”Not exist”

利用判断符号 [ ]

如果我想要知道 $HOME 这个变量是否为空的,可以这样做:

[root@www ~]# [ -z "$HOME" ] ; echo $?

注意中括号的两端需要有空白字节来分隔!

在中括号 [] 内的每个组件都需要有空白键来分隔;
在中括号内的变量,最好都以双引号括号起来;
在中括号内的常数,最好都以单或双引号括号起来。

Shell script 的默认变量($0, $1…)

运行的脚本档名为 $0 变量,第一个接的参数就是 $1,依次类推。

其他特殊变量:

$# :代表后接的参数『个数』;
$@ :代表『 "$1" "$2" "$3" "$4" ...』之意,每个变量是独立的(用双引号括起来);
$* :代表『 "$1c$2c$3c$4..." 』,其中 c 为分隔字节,默认为空白键。

shift:造成参数变量号码偏移

shift 后面可以接数字,代表拿掉最前面的几个参数的意思

利用 if …. then

[root@www scripts]# vi sh09.sh
#!/bin/bash
# Program:
# Check $1 is equal to "hello"
# History:
# 2005/08/28 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

if [ "$1" == "hello" ]; then
echo "Hello, how are you ?"
elif [ "$1" == "" ]; then
echo "You MUST input parameters, ex> {$0 someword}"
else
echo "The only parameter is 'hello', ex> {$0 hello}"
fi

利用 case ….. esac 判断

[root@www scripts]# vi sh12.sh
#!/bin/bash
# Program:
# This script only accepts the flowing parameter: one, two or three.
# History:
# 2005/08/29 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

echo "This program will print your selection !"
case $1 in # 现在使用,可以用上面两行替换!
"one")
echo "Your choice is ONE"
;;
"two")
echo "Your choice is TWO"
;;
"three")
echo "Your choice is THREE"
;;
*)
echo "Usage $0 {one|two|three}"
;;
esac

利用 function 功能

[root@www scripts]# vi sh12-3.sh
#!/bin/bash
# Program:
# Use function to repeat information.
# History:
# 2005/08/29 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

function printit(){
echo "Your choice is $1" # 这个 $1 必须要参考底下命令的下达
}

echo "This program will print your selection !"
case $1 in
"one")
printit 1 # 请注意, printit 命令后面还有接参数!
;;
"two")
printit 2
;;
"three")
printit 3
;;
*)
echo "Usage $0 {one|two|three}"
;;
esac

循环

while do done, until do done (不定次数循环)

while [ condition ]  <==中括号内的状态就是判断式
do <==do 是循环的开始!
程序段落
done <==done 是循环的结束

until [ condition ]
do
程序段落
done

for…do…done (固定次数循环)

for var in con1 con2 con3 ...
do
程序段
done

for…do…done 的数值处理

for (( 初始值; 限制值; 运行步阶 ))
do
程序段
done


[root@www scripts]# vi sh19.sh
#!/bin/bash
# Program:
# Try do calculate 1+2+....+${your_input}
# History:
# 2005/08/29 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

read -p "Please input a number, I will count for 1+2+...+your_input: " nu

s=0
for (( i=1; i<=$nu; i=i+1 ))
do
s=$(($s+$i))
done
echo "The result of '1+2+3+...+$nu' is ==> $s"

shell script 的追踪与 debug

[root@www ~]# sh [-nvx] scripts.sh
选项与参数:
-n :不要运行 script,仅查询语法的问题;
-v :再运行 sccript 前,先将 scripts 的内容输出到萤幕上;
-x :将使用到的 script 内容显示到萤幕上,这是很有用的参数!