编写shell脚本需要注意:
1. 指令的执行是从上而下、从左而右的分析与执行;
2. 指令、选项与参数间的多个空格都会被忽略;
3. 空白行也将被忽略掉,并且[tab]按键所推开的空白同样规为空格键;
4. 如果读取到一个Enter符号(CR),就尝试开始执行该行(或该串)命令;
5. 至于如果一行的内容太多,则可以使用『\[Enter]』来延伸至下一行;
6. 『#』注释
第一支shell程序
#!/bin/bash
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名称:
因为我们使用的是 bash ,所以,必须要以『 #!/bin/bash 』来宣告这个档案内的语法使用 bash 的语法!那么当这个程序被执行时,他就能够加载 bash 的相关环境配置文件 (一般来说就 是 non-login shell 的 ~/.bashrc), 并且执行 bash 来使我们底下的指令能够执行!这很重要 的!(在很多状况中,如果没有设定好这一行, 那么该程序很可能会无法执行,因为系统可能无法判断该程序需要使用什么 shell 来执行!) -
程序内容的说明:
整个 script 当中,除了第一行的『 #! 』是用来宣告 shell 的之外,其他的 # 都是『批注』用途! -
执行成果告知(定义回传值)
exit N(数字)
第二支shell程序
#!/bin/bash
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"
执行完 sh sh02.sh 后打印echo $firstname,不存在。
直接指令下达 (不论是绝对路径/相对路径还是 $PATH 内),获取是利用 bash (或 sh) 来下达脚本时, 该 script 都会使用一个新的 bash 环境来执行脚本内的指令
当你使用直接执行的方法来处理 时,系统会给予一支新的 bash 让我们来执行 sh02.sh 里面的指令,因此你的 firstname, lastname 等变量其实是在下图中的子程序 bash 内执行的。 当 sh02.sh 执行完毕后,子程序 bash 内的所有数据便被移除,因此,在父程序底下 echo $firstname 时, 就看不到任何东西了!
利用 source 来执行脚本:在父程序中执行
source sh02.sh,程序执行完成后,打印echo $firstname,便存在了。
总结:父进程想要使用子进程中的变量,需要用source来执行子程序。子进程中想使用父进程中的自定义变量(父进程中的环境变量可直接供子进程使用),则需要在父进程中export自定义变量
第三支shell程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "I will use 'touch' command to create 3 files."
read -p "Please input your filename: " fileuser
filename=${fileuser:-"filename"}
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}
touch "$file1"
touch "$file2"
touch "$file3"
第四支shell程序
#!/bin/bash
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"
第五支shell程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "Please input a filename, I will check the filename's type and \ permission. \n\n"
read -p "Input a filename : " filename
test -z $filename && echo "You MUST input a filename." && exit 0
test ! -e $filename && echo "The filename '$filename' DO NOT exist" && exit 0
test -f $filename && filetype="regulare file"
test -d $filename && filetype="directory"
test -r $filename && perm="readable"
test -w $filename && perm="$perm writable"
test -x $filename && perm="$perm executable"
echo "The filename: $filename is a $filetype"
echo "And the permissions are : $perm"
利用 test 指令的测试功能
利用判断符号 [ ]
使用中括号必须要特别注意,因为中括号用在很多地方,包括通配符与正规表示法等等,所以如果要在 bash 的语法当中使用中括号作为 shell 的判断式时,必须要注意中括号的两端需要有空格符来分割!
-
在中括号 [] 内的每个组件都需要有空格来分割;
-
在中括号内的变量,最好都以双引号括号起来;
-
在中括号内的常数,最好都以单或双引号括号起来。
第六支shell程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "Please input (Y/N): " yn
[ "$yn" == "Y" -o "$yn" == "y" ] && echo "OK, continue" && exit 0
[ "$yn" == "N" -o "$yn" == "n" ] && echo "Oh, interrupt!" && exit 0
echo "I don't know what your choice is" && exit 0
-o或的意思
第七支shell程序
为脚本传递参数
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo "The script name is ==> $0"
echo "Total parameter number is ==> $#"
[ "$#" -lt 2 ] && echo "The number of parameter is less than 2. Stop here." && exit 0
echo "Your whole parameter is ==> '$@'"
echo "The 1st parameter ==> $1"
echo "The 2nd parameter ==> $2"
第八支程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo "Total parameter number is ==> $#"
echo "Your whole parameter is ==> '$@'"
shift
echo "Total parameter number is ==> $#"
echo "Your whole parameter is ==> '$@'"
shift 3
echo "Total parameter number is ==> $#"
echo "Your whole parameter is ==> '$@'"
shift 会移动变量,而且 shift 后面可以接数字,代表拿掉最前面的几 个参数的意思。
条件判断
利用 if .... then
单层、简单条件判断
[ "$yn" == "Y" -o "$yn" == "y" ] 上式可替换为[ "$yn" == "Y" ] || [ "$yn" == "y" ]
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "Please input (Y/N): " yn
if [ "$yn" == "Y" ] || [ "$yn" == "y" ];
then echo "OK, continue"
exit 0
fi
if [ "$yn" == "N" ] || [ "$yn" == "n" ];
then echo "Oh, interrupt!"
exit 0
fi
echo "I don't know what your choice is" && exit 0
多重、复杂条件的条件判断
或
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "Please input (Y/N): " yn
if [ "$yn" == "Y" ] || [ "$yn" == "y" ];
then echo "OK, continue"
elif [ "$yn" == "N" ] || [ "$yn" == "n" ];
then echo "Oh, interrupt!"
else
echo "I don't know what your choice is"
fi
第九支shell程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo "Now, I will detect your Linux server's services!"
echo -e "The www, ftp, ssh, and mail will be detect! \n"
testing=$(netstat -tuln | grep ":80 ")
if [ "$testing" != "" ]; then
echo "WWW is running in your system."
fi
testing=$(netstat -tuln | grep ":22 ")
if [ "$testing" != "" ]; then
echo "SSH is running in your system."
fi
testing=$(netstat -tuln | grep ":21 ")
if [ "$testing" != "" ]; then
echo "FTP is running in your system."
fi
testing=$(netstat -tuln | grep ":25 ")
if [ "$testing" != "" ]; then
echo "Mail is running in your system."
fi
利用 case ..... esac 判断
第十支shell程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
case $1 in "hello")
echo "Hello, how are you ?"
;;
"")
echo "You MUST input parameters, ex> {$0 someword}"
;;
*) # 其实就相当亍通配符,0~无穷多个任意字符之意!
echo "Usage $0 {hello}"
;;
esac
函数function
因为 shell script 的执行方式是由上而下,由左而右, 因此在 shell script 当中的 function 的设定一 定要在程序的最前面, 这样才能够在执行时被找到可用的程序段
第十一支shell程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
function printit(){
echo -n "Your choice is " # 加上 -n 可以不断行继续在同一行显示
}
echo "This program will print your selection !"
case $1 in "one")
printit;
echo $1 | tr 'a-z' 'A-Z'
;;
"two")
printit;
echo $1 | tr 'a-z' 'A-Z'
;;
"three")
printit;
echo $1 | tr 'a-z' 'A-Z'
;;
*)
echo "Usage $0 {one|two|three}"
;;
esac
注意:
function 也是拥有内建变量的~他的内建变量与 shell script 很类似, 函数名称代表示 $0 , 而后续接的变量也是以 $1, $2... 来取代的~ 这里很容易搞错~因为『 function fname() { 程序段 } 』内的 $0, $1... 等等与 shell script 的 $0 是不同的。
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
function printit(){
echo "Your choice is $1"
}
echo "This program will print your selection !"
case $1 in
"one")
printit 1
;;
"two")
printit 2
;;
"three")
printit 3
;;
*)
echo "Usage $0 {one|two|three}"
;;
esac
循环(loop)
第十二支shell程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
while [ "$yn" != "yes" -a "$yn" != "YES" ]
do
read -p "Please input yes/YES to stop this program: " yn
done
echo "OK! you input the correct answer."
第十三支shell程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
until [ "$yn" == "yes" -o "$yn" == "YES" ]
do
read -p "Please input yes/YES to stop this program: " yn
done
echo "OK! you input the correct answer."
第十四支shell程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
s=0
i=0
while [ "$i" != "100" ]
do
i=$(($i+1))
s=$(($s+$i))
done
echo "The result of '1+2+3+...+100' is ==> $s"
第十五支shell程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
for animal in dog cat elephant
do
echo "There are ${animal}s.... "
done
第十六支shell程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
users=$(cut -d ':' -f1 /etc/passwd)
for username in $users
do
id $username
done
第十七支shell程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
network="192.168.1"
for sitenu in $(seq 1 100)
do
ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 || result=1
if [ "$result" == 0 ];
then
echo "Server ${network}.${sitenu} is UP."
else
echo "Server ${network}.${sitenu} is DOWN."
fi
done
第十八支shell程序
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "Please input a directory: " dir
if [ "$dir" == "" -o ! -d "$dir" ];
then
echo "The $dir is NOT exist in your system."
exit 1
fi
filelist=$(ls $dir)
for filename in $filelist
do
perm=""
test -r "$dir/$filename" && perm="$perm readable"
test -w "$dir/$filename" && perm="$perm writable"
test -x "$dir/$filename" && perm="$perm executable"
echo "The file $dir/$filename's permission is $perm "
done
第十九支shell程序
#!/bin/bash
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脚本的追踪与调试