shell 脚本-符号-基础语法
为了便于识别 建议 以.sh 结尾
shell脚本 可以放上所有的命令行的指令(源于bash)
shell脚本 是 解释型语言 c/c++ 是编译型语言
下面用到的 shell代码sh_1.sh
#!/bin/bash cd ../ ls pwd
解释型脚本的执行过程:
script.sh 是文本文件,根本没有代码段和 _start 函数 , exec 怎么执行。
解释:
Shell会fork 一个子进程并调用 exec执行 ./script.sh这个程序,exec 系统调用应该把子进程的代码
段替换成./script.sh程序的代码段 ,并从它的 _start开始执行。然而 script.sh是个文本文件,根 本
没有代码段和 _start函数 ,怎么办呢 ?其实 exec还有另外一种机制 ,如果要执行的是一个文本文
件, 并且第一行用 Shebang 指定了解释器 ,则用 解释器程序的代码段替换当前进程 ,并且从解释
器 的_start开始执行 ,而这个文本文件被当作命令行参数传给解释器 。因此, 执行上述脚本相
当于执 行程序
1. 交互 Shell(bash)fork/exec一个子 Shell(sh)用于执行脚本 ,父进程 bash等待子进程 sh终止。
2. sh读取脚本中的 cd ..命令 ,调用相应的函数 执行内建命令 ,改变当前工作目录为上一级
目 录。
3. sh读取脚本中的 ls命令 ,fork/exec这个程序 ,列出当前工作目录下的文件 ,sh等待 ls终止。
4. ls终止后 ,sh继续执行 ,读到脚本文件末尾 ,sh终止。
5. sh终止后 ,bash继续执行 ,打印提示符等待用户输入。
如果将命令行下输入的命令用 ()括号括起来 ,那么也会 fork出一个子 Shell执行小括号中的命令 ,
一 行中可以输入由分号 ;隔开的多个命令 ,比如 : $ (cd ..;ls -l)
和上面两种方法执行 Shell脚本的效果是相同的 ,cd ..命令改变的是子 Shell的 PWD,而不会影响
到 交互式Shell。
chmod + x script.sh方式
sh文件中,cd ..命令改变的是子Shell的PWD,而不会影响到 交互式Shell1(对于文件sh, 交互式shell1会先创建一个子shell2,子shell2会再创建一个shell3,shell3遇见cd命令 会直接由shell2执行,改变的是shell2的路径,shell1的路径不变)。
然而source ./script.sh 和 . ./script.sh 方式
则有不同的效果,cd ..命令是直接在交互式Shell1下执行的,改变交互式Shell的PWD
对于php 。。。脚本语言 执行也是 解释器这个流程
sh_1.sh代码:
#!/bin/bash
cd ../
ls
pwd
[bozi@localhost 1_shell]$ /bin/bash sh_1.sh // shell脚本中 cd 直接在子bash中运行 整个过程父进程 不参与
1_shell
/home/bozi/linux_test/shell
[bozi@localhost 1_shell]$ pwd
/home/bozi/linux_test/shell/1_shell // 所以 不影响父进程 的路径 还在子进程的路径中
[bozi@localhost 1_shell]$ cd .. // cd内置命令 shell 自己直接亲自执行(不创建子进程) 影响自己的路径
[bozi@localhost shell]$ pwd
/home/bozi/linux_test/shell // 直接执行 影响了 跑到上级目录
路径
[bozi@localhost shell]$ ll
总用量 4
drwxrwxr-x. 2 bozi bozi 4096 8月 14 10:18 1_shell
[bozi@localhost shell]$ cd 1_shell/
[bozi@localhost 1_shell]$ ll
总用量 4
-rw-rw-r--. 1 bozi bozi 298 8月 14 10:18 sh_1.sh
source 与(. 命令一样)
例子:
source 不创建子bash,遇见bash中有内建命令 cd 交互式shell(父进程自己直接执行) 所以 退出时 父进程的路径 变了 影响父进程
[bozi@localhost 1_shell]$ ll
总用量 4
-rw-rw-r--. 1 bozi bozi 298 8月 14 10:18 sh_1.sh
[bozi@localhost 1_shell]$ source sh_1.sh
1_shell
/home/bozi/linux_test/shell
[bozi@localhost shell]$ pwd
/home/bozi/linux_test/shell
.命令 效果相同
[bozi@localhost 1_shell]$ . sh_1.sh
1_shell
/home/bozi/linux_test/shell
[bozi@localhost shell]$ pwd
/home/bozi/linux_test/shell
set 显示 本地变量 和 环境变量(本地变量只存在当前进程中)
env 只显示环境变量 (环境变量 可以传递给 子进程 父子进程共享)
变量
shell 中 所有变量varname都是字符串 ,且都是全局本地变量 没有int ,float等类型 显示变量 用 $varname或 ${varname}
如果变量不存在 shell显示空串
变量拼接 用{}花括号 如: ${varname}aaa $varname"aaa"
演示代码:
[bozi@localhost 2_shell]$ SHELL=1 [bozi@localhost 2_shell]$ echo $SHELL 1 [bozi@localhost 2_shell]$ echo $SHELLabc [bozi@localhost 2_shell]$ echo ${SHELL} 1 [bozi@localhost 2_shell]$ echo ${SHELL}abc 1abc
unset 取消一个变量
[root@localhost 2_shell]# v=a [root@localhost 2_shell]# echo $v a [root@localhost 2_shell]# unset $v [root@localhost 2_shell]#
显示本shell的pid
[root@localhost 2_shell]# echo $$ 6699
read
-p 提示符 -t 等待的秒数
[bozi@localhost 2_shell]$ read -p ‘>>‘ -t 10 arg >>nihao [bozi@localhost 2_shell]$ echo $arg nihao
数组变量
var[1]="small min" var[2]="big min" var[3]="nice min" echo "${var[1]}, ${var[2]},${var[3]}" [bozi@localhost 2_shell]$ ./1_test.sh small min, big min,nice min
test指令
两个整数之间的判定
-eq 相等(equal)
-ne 不等(not equal)
-gt 大于 (greaater than)
-lt 小于 (less than)
-ge 大于等于 (greater than or equal)
-le 小于等于 (less than or equal)
例子:
[bozi@localhost 2_shell]$ test 1 -lt 2; echo $? 0 ---------------》【真】 [bozi@localhost 2_shell]$ test 5 -lt 2; echo $? 1
判定字符串的数据
test -z string [string 为空 返回true] test -n string [string 为空 返回false] test str1 = str2 [str1=str2 回传true] test str1 != str2 [str1 与str2相等返回 false] 例子: [bozi@localhost 2_shell]$ test -z "";echo $? 0 [bozi@localhost 2_shell]$ test -z "-";echo $? 1 [bozi@localhost 2_shell]$ test -n "";echo $? 1 [bozi@localhost 2_shell]$ test -n "-";echo $? 0 [bozi@localhost 2_shell]$ test "nihao" = "hello" ; echo $? 1 [bozi@localhost 2_shell]$ test "nihao" == "hello" ; echo $? 1 [bozi@localhost 2_shell]$ test "nihao" != "hello" ; echo $? 0
error
[bozi@localhost 2_shell]$ test "nihao"=="hello" ; echo $?
0 ----》“==两边少空格 结果 不正确”
test扩展:
当要检测系统上面某些文件或者是相关的属性时,利用test这个命令来工作真是好用得不得了,如检查/dmtsai是否存在时,使用:test –e /dmtsai
上面的执行结果并不会显示任何信息,但最后可以通过$?或&&及||来显示整个结果。
test –e /dmtsai && echo “exist” ||echo “Not exist”
最终结果可以显示exist还是not exist。-e是测试一个东西存在不存在。常用的测试命令如下:
测试的标志 | 代表意义 |
关于某个文件名的“文件类型”判断,如test – e filename表示存在否 | |
-e | 该文件名是否存在 |
-f | 该文件名是否存在且为文件(file) |
-d | 该文件名是否存在且为目录(directory) |
-b | 该文件名是否存在且为一个block device设备 |
-c | 该文件名是否存在且为一个character device设备 |
-S | 该文件名是否存在且为一个Socket文件 |
-p | 该文件名是否存在且为一个FIFO(pipe)文件 |
-L | 该文件名是否存在且为一个连接文件 |
关于文件的权限检测,如test –r filename表示可读否(但root权限常有例外) | |
-r | 检测该文件名是否存在且具有“可读”的权限 |
-w | 检测该文件名是否存在且具有“可写”的权限 |
-x | 检测该文件名是否存在且具有“可执行”的权限 |
-u | 检测该文件名是否存在且具有“SUID”的属性 |
-g | 检测该文件名是否存在且具有“SGID“的属性 |
-k | 检测该文件名是否存在且具有“Sticky bit”的属性 |
-s | 检测该文件名是否存在且具有“非空白文件” |
两个文件之间的比较,如test file1 –nt file2 | |
-nt | (newer than)判断file1是否比file2新 |
-ot | (older than)判断file1是否比file2旧 |
-ef | 判断file1与file2是否为同一文件,可用在判断hard link的判定上。主要意义在于判定两个文件是否均指向同一个inode |
关于两个整数之间的判定吗,如test n1 –eq n2 | |
-eq | 两数值相等(equal) |
-ne | 两数值不等(not equal) |
-gt | N1大于n2(greate than) |
-lt | N1小于n2(less than) |
-ge | N1大于等于n2(greater than or equal) |
-le | N1小于等于n2(less than or equal) |
判定字符串的数据 | |
test –z string | 判定字符串是否为0,若string为空字符串,则为true |
test –n string | 判定字符串是否非为0,若string为空字符串,则为false |
test str1 = str2 | 判定str1是否等于str2,若相等,则回传true |
test str1 != str2 | 判定str1是否不等于str2,若相等,则回传false |
多重条件判定,若test –r filename –a –x filename | |
-a | 两个条件同时成立!如test –r file –a –x file,则file同时具有r与x权限时,才回传true |
-o | 任何一个条件成立!如test –r file –o –x file,则file具有r或x权限时,就可回传true |
! | 反向状态,如test ! –x file,但file不具有x时,回传true |
多重条件判定
-a [先当于 与&&]
-o 【或】
! 【非】
例子:
[bozi@localhost 2_shell]$ test 1 -eq 1 -a 2 -lt 5; echo $? 0 [bozi@localhost 2_shell]$ test 1 -eq 1 -a 5 -lt 2; echo $? 1
判断符号[]
[bozi@localhost 2_shell]$ [ "" == "HOME" ];echo $? 1 [bozi@localhost 2_shell]$ [ "" != "HOME" ];echo $? 0
error
[bozi@localhost 2_shell]$ [ ""!="HOME" ];echo $? 0 [bozi@localhost 2_shell]$ [ ""=="HOME" ];echo $? 0
注意 空格不能少 否则出错:
[bozi@localhost 2_shell]$ [ 空格"" 空格== 空格"HOME" 空格];echo $?
建议:
1 在中括号[]中的每个组件用 空格 隔开
2 在中括号内的变量, 最好用双引号括起来
3 在中括号里面的常量最好用单引号或 双引号括起来
2的一个错误例子:
[bozi@localhost 2_shell]$ name="hello world" [bozi@localhost 2_shell]$ [ $name == "hello" ] bash: [: too many arguments --------------------------》 太多参数 本来是两个参数比较 因为name变量的字符串中间有空格 不加“” 解析为 [ hello world == "hello" ] 肯定参数太多 [bozi@localhost 2_shell]$ [ "$name" == "hello" ] [bozi@localhost 2_shell]$ echo $? 1 [bozi@localhost 2_shell]$ [ "$name" != "hello" ] [bozi@localhost 2_shell]$ echo $? 0
小练习:
read -p "please inoput (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 dont know what your chonice is " && exit 0 运行: [bozi@localhost 2_shell]$ ./1_test.sh please inoput (Y/N):y ok, continue [bozi@localhost 2_shell]$ ./1_test.sh please inoput (Y/N):n oh, interrupt [bozi@localhost 2_shell]$ ./1_test.sh please inoput (Y/N): I dont know what your chonice is
shell中&&和||的使用方法
&&运算符:
command1 && command2
&&左边的命令(命令1)返回真(即返回0,成功被执行)后,&&右边的命令(命令2)才能够被执行;换句话说,“如果这个命令执行成功&&那么执行这个命令”。
语法格式如下:
command1 && command2 [&& command3 ...]
1 命令之间使用 && 连接,实现逻辑与的功能。
2 只有在 && 左边的命令返回真(命令返回值 $? == 0),&& 右边的命令才会被执行。
3 只要有一个命令返回假(命令返回值 $? == 1),后面的命令就不会被执行。
||运算符:
command1 || command2
||则与&&相反。如果||左边的命令(命令1)未执行成功,那么就执行||右边的命令(命令2);或者换句话说,“如果这个命令执行失败了||那么就执行这个命令。
1 命令之间使用 || 连接,实现逻辑或的功能。
2 只有在 || 左边的命令返回假(命令返回值 $? == 1),|| 右边的命令才会被执行。这和 c 语言中的逻辑或语法功能相同,即实现短路逻辑或操作。
3 只要有一个命令返回真(命令返回值 $? == 0),后面的命令就不会被执行。
&& || 与 -a -o
区别
-a -o 连接的是两个表达式 即 测试条件
而 && 与 || 连接的是两条 命令
代码:
val=10 str="hello" test $val -eq 10 -a "$str" == "hello" echo $? test $val -eq 10 && test "$str" == "hello" echo $? 运行: [bozi@localhost 2_shell]$ ./12_test.sh 0 0
默认变量 $0 $1 $2 ...
例子:$ ./1_test.sh nihao sunshine
$0 $1 $2
$# :代表后接的参数的个数, 如上例子为2
$@:代表"$1" "$2" ... 之意, 每个变量独立的用双括号括起来
$*: 代表“$1c$2c$3c$4” c为分隔符号,默认是空格键
$@ 和 $*还是有所不同的 一般用 $@
代码:
#! /bin/bash echo "\$0 is $0" echo "\$1 is $1" echo "\$2 is $2" echo "\$# is $#" echo "\$@ is $@" echo "\$* is $*"
运行:
[bozi@localhost 2_shell]$ ./1_test.sh $0 is ./1_test.sh $1 is $2 is $# is 0 $@ is $* is
[bozi@localhost 2_shell]$ ./1_test.sh 1 2 3 4 $0 is ./1_test.sh $1 is 1 $2 is 2 $# is 4 $@ is 1 2 3 4 $* is 1 2 3 4
代码:
echo "your whole parameter is ===>$0" echo "total parameter numbers is ===>$#" [ "$#" -lt 2 ]&&echo "the numbers of paramater is less than 2. stop here"&& exit 0; echo "your whole parameter is ===>$@" echo "the 1st parameter ===>$1" echo "the 2nd parameter ===> $2 "
运行:
[bozi@localhost 2_shell]$ ./1_test.sh your whole parameter is ===>./1_test.sh total parameter numbers is ===>0 the numbers of paramater is less than 2. stop here [bozi@localhost 2_shell]$ ./1_test.sh nihao sunshine your whole parameter is ===>./1_test.sh total parameter numbers is ===>2 your whole parameter is ===>nihao sunshine the 1st parameter ===>nihao the 2nd parameter ===> sunshine
运行:
[bozi@localhost 1_shell]$ cat sh_1.sh #!/bin/bash myint=10 echo ‘\$ \\ $myint \"‘ echo ‘###############‘ echo "\$ \\ $myint \"" [bozi@localhost 2_shell]$ ./1_test.sh your whole parameter is ===>./1_test.sh total parameter numbers is ===>0 the numbers of paramater is less than 2. stop here [bozi@localhost 2_shell]$ ./1_test.sh nihao sunshine your whole parameter is ===>./1_test.sh total parameter numbers is ===>2 your whole parameter is ===>nihao sunshine the 1st parameter ===>nihao the 2nd parameter ===> sunshine [bozi@localhost 2_shell]$ ./1_test.sh nihao sunshine here your whole parameter is ===>./1_test.sh total parameter numbers is ===>3 your whole parameter is ===>nihao sunshine here the 1st parameter ===>nihao the 2nd parameter ===> sunshine
shift:造成参数号码偏移,移除前num个参数
shift+num num 及num之前的参数全部移除 num之后的参数从$1开始
如:
echo $@ echo "arg count $#" shift 1 echo "after shift 1" echo $@ echo "arg count $#" shift 3 echo "after shift 3" echo $@ echo "arg count $#"
运行:
[bozi@localhost 2_shell]$ ./1_test.sh one two three four five six seven one two three four five six seven arg count 7 after shift 1 two three four five six seven arg count 6 after shift 3 five six seven arg count 3
条件判断式
1 if ... then
if [条件判断式];then
条件成立执行
fi
&&代表AND
|| 代表 or
代码:
#!/bin/bash read -p "please input (Y/N):" yn if [ "X$yn" == "XY" ] || [ "X$yn" == "Xy" ];then echo "ok, continue" exit 0 fi if [ "X$yn" == "XN" ] || [ "X$yn" == "Xn" ];then echo "oh, interupt!" exit 0 fi
运行:
please input (Y/N):y ok, continue [bozi@localhost 2_shell]$ ./2_test.sh please input (Y/N):Y ok, continue [bozi@localhost 2_shell]$ ./2_test.sh please input (Y/N):N oh, interupt! [bozi@localhost 2_shell]$ ./2_test.sh please input (Y/N):n oh, interupt!
多重复杂条件判断式
if [条件判断式];then
条件成立
else
...
if
if [条件判断式1];then
...
elif [条件判断式2];then
...
else
...
if
代码:
read -p "please input (Y/N):" yn if [ "x$yn" == "xY" ] || [ "x$yn" == "xy" ]; then echo "ok, continue" elif [ "x$yn" == "xN" ] || [ "x$yn" == "xn" ]; then echo "oh, interupt" else echo "I dont know what your choice is" fi
运行:
[bozi@localhost 2_shell]$ vim 2_test.sh [bozi@localhost 2_shell]$ ./2_test.sh please input (Y/N):y ok, continue [bozi@localhost 2_shell]$ ./2_test.sh please input (Y/N):n oh, interupt [bozi@localhost 2_shell]$ ./2_test.sh please input (Y/N):s I dont know what your choice is 代码: testing=$(netstat -tuln |grep ‘:80‘ ) if [ "X$testing" != "X" ];then echo "WWW is running in your system ." fi testing=$(netstat -tuln | grep ‘:22‘) if [ "X$testing" != "X" ]; then echo "SSH is running in your system." fi testing=$(netstat -tuln | grep ‘:21‘) if [ "X$testing" != "X" ]; then echo "FTP is running in your system." fi testing=$(netstat -tuln | grep ‘:25‘) if [ "X$tesing" != "X" ]; then echo "Mail is running in your system." fi
运行:
[bozi@localhost 2_shell]$ ./3_text.sh Now, I will detect your linux server‘s services! The wwww, ftp, ssh , and mail will be detect ! SSH is running in your system.
利用case ...... esac判断
case $变量名称 in
”第1个变量名称“)
程序段
;;
”第2个变量名称“)
程序段
;; # ;; 相当于break
*) #*)相当于default
程序段
;;
esac
代码:
#!/bin/bash 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
运行:
[bozi@localhost 2_shell]$ ./4_test.sh Usage ./4_test.sh {one|two|three} [bozi@localhost 2_shell]$ ./4_test.sh one your choice is ONE [bozi@localhost 2_shell]$ ./4_test.sh two your choice is TWO [bozi@localhost 2_shell]$ ./4_test.sh three your choice is THREE
函数 function
函数的参数 也是$1$2$.... 但是函数体里面的$1$2...与函数外面的 是相对独立的
函数返回值: return后 用 $? 来接收 【返回值】(缺陷 返回257 是 1 范围0-255)
代码:
#!/bin/bash function printit() # 也可以不加关键字function 即 printit(){...} 也是可以的 { echo -n "Your choice is " #加上-n表示不断行继续在一行显示 } 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
运行:
[bozi@localhost 2_shell]$ ./5_test.sh one Your choice is ONE [bozi@localhost 2_shell]$ ./5_test.sh Usage ./5_test.sh {one|two|three} [bozi@localhost 2_shell]$ ./5_test.sh one Your choice is ONE [bozi@localhost 2_shell]$ ./5_test.sh two Your choice is TWO [bozi@localhost 2_shell]$ ./5_test.sh three Your choice is THREE
经典的fork炸弹 【!!!立马宕机】
.() { .|.& }; . #递归调用 后台执行
类似的 function a() { a|a }; a
防范措施 ulimit -Hu num 限定用户最多num个进程
-------------------------------------------------
以下程序段就是由Jaromil所作的在类UNIX系统的shell环境下触发fork炸弹的shell脚本代码,总共只用了13个字符(包括空格):
:(){ :|:& };:
注解如下:
:() # 定义函数,函数名为":",即每当输入":"时就会自动调用{}内代码
{ # ":"函数开始标识
: # 用递归方式调用":"函数本身
| # 并用管道(pipe)将其输出引至...
: # 另一次递归调用的":"函数
# 综上,":|:"表示的即是每次调用函数":"的时候就会生成两份拷贝【二倍指数增长】
& # 调用间脱钩,以使最初的":"函数被杀死后为其所调用的两个":"函数还能继续执行
} # ":"函数结束标识
; # ":"函数定义结束后将要进行的操作...
: # 调用":"函数,"引爆"fork炸弹
其中函数名“:”只是简化的一例,实际实现时可以随意设定,一个较易理解(将函数名替换为“forkbomb”)的版本如下:
forkbomb(){ forkbomb|forkbomb &} ; forkbomb
Windows下则可以批处理命令如下实现:
%0|%0
POSIX标准下的C与C++的实现:
#include <unistd.h>int main(){while(1) fork();return0;}
Perl语言的实现:
fork while fork
-------------------------------------------------
循环
while do done, until do done(不定循环)
代码:
#!/bin/bash while [ "X$yn" != "Xyes" -a "X$yn" != "XYES" ] do read -p "please input yes/YES to stop this program:" yn done echo "ok, you input the correct answer."
运行:
[bozi@localhost 2_shell]$ chmod u+x 6_test.sh [bozi@localhost 2_shell]$ ./6_test.sh please input yes/YES to stop this program:e please input yes/YES to stop this program:e please input yes/YES to stop this program:yes ok, you input the correct answer.
until代码:
sum=0 i=0 until [ $i -gt 100 ] do if (( i%2==0 ));then let sum+=i fi: let i++ done echo $sum
运行:
[bozi@localhost 2_shell]$ ./6_test.sh 2550 代码: s=0 i=0 while [ "$i" != "100" ] do i=$(($i+1)) s=$(($s+$i)) done echo "sum of 1+2+3+...+100 is : $s"
运行:
[bozi@localhost 2_shell]$ ./7_test.sh sum of 1+2+3+...+100 is : 5050
for ... do... done(固定循环)
for var in con1 con2 con3 ...
do
程序段
done
代码:
for animal in dog cat elephant do echo "there are ${animal}s..." done 运行: [bozi@localhost 2_shell]$ ./8_test.sh there are dogs... there are cats... there are elephants...
代码:
users=$(cut -d‘:‘ -f1 /etc/passwd) for username in $users do id $username done
运行:
[bozi@localhost 2_shell]$ ./9_test.sh uid=0(root) gid=0(root) 组=0(root) uid=1(bin) gid=1(bin) 组=1(bin),2(daemon),3(sys) uid=2(daemon) gid=2(daemon) 组=2(daemon),1(bin),4(adm),7(lp) uid=3(adm) gid=4(adm) 组=4(adm),3(sys) uid=4(lp) gid=7(lp) 组=7(lp) uid=5(sync) gid=0(root) 组=0(root)
测ip代码:
read -p "enter like 192.168.1->" network 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
运行:
[bozi@localhost 2_shell]$ ./9_test.sh enter like 192.168.1->192.168.174 server 192.168.174.1 is up. server 192.168.174.2 is up. server 192.168.174.3 is down server 192.168.174.4 is down server 192.168.174.5 is down server 192.168.174.6 is down server 192.168.174.7 is down
代码:
#!/bin/bash read -p "please input a diretory:" dir if [ "$dir" == "" -o ! -d "$dir" ];then echo "then $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
运行:
[bozi@localhost 2_shell]$ ./10_test.sh please input a diretory:../1_shell the file ../1_shell/2‘s permission is readable writable the file ../1_shell/3‘s permission is readable writable the file ../1_shell/sh_1.sh‘s permission is readable writable the file ../1_shell/sh_2.sh‘s permission is readable writable executable
for ....do...done 的数值处理
for ((初始值; 限制值;执行步阶))
do
程序段
done
这种写法 适合在数值运算中
代码:
read -p "please input a number . I will count for 1+2+3+...+your_input" num s=0 for ((i=1; i <= $num; i++)) do ((s += i)) done echo "the result of ‘1+2+3+...+$num ‘is $s"
运行:
[bozi@localhost 2_shell]$ ./11_test.sh please input a number . I will count for 1+2+3+...+your_input10 the result of ‘1+2+3+...+10 ‘is 55 代码: #!/bin/bash for i in {A..b} do echo "val is: $i" done
运行:
[bozi@localhost 2_shell]$ sh 14_test.sh val is: A val is: B val is: C val is: D val is: E val is: F val is: G val is: H val is: I val is: J val is: K val is: L val is: M val is: N val is: O val is: P val is: Q val is: R val is: S val is: T val is: U val is: V val is: W val is: X val is: Y val is: Z val is: [ val is: val is: ] val is: ^ val is: _ val is: ` val is: a val is: b
shell script 的 追踪 与 debug
-n : 不执行script,仅查询语法错误
-v: 在执行script之前,现将script的内容输出到屏幕上
-x: 将使用到的script内容显示到屏幕上
代码:
检查是否有语法问题 没有问题就什么也不输出
运行:
[bozi@localhost 2_shell]$ sh -n 12_test.sh
[bozi@localhost 2_shell]$
代码:
将使用到的代码显示出来
运行:
[bozi@localhost 2_shell]$ sh -x 12_test.sh + val=10 + str=hello + test 10 -eq 10 -a hello == hello + echo 0 0 + test 10 -eq 10 + test hello == hello + echo 0 0
一是在命令行提供参数
$ sh -x ./script.sh
二是在脚本开头提供参数
#! /bin/sh -x
第三种方法是在脚本中用 set命令启用或禁用参数
set -x和set +x 分别表示启用和禁用 -x参数 ,这样可以只对脚本中的某一段进行跟踪调试。
代码:
val=10 str="hello" set -x test $val -eq 10 -a "$str" == "hello" echo $? set +x test $val -eq 10 && test "$str" == "hello" echo $?
运行:
[bozi@localhost 2_shell]$ sh -x 12_test.sh + val=10 + str=hello + set -x + test 10 -eq 10 -a hello == hello + echo 0 0 + set +x 0
:是一个特殊的命令,称为空命令 ,该命令不做任何事,但 Exit Status总是真。此外 ,也可以执 行
/bin/true或 /bin/false得到真或假的 Exit Status。
文件名替换
这些用于匹配的字符称为通配符 (Wildcard),具体如下 :
通配符 * : 匹配 0个或多个 任意字符
? : 匹配 一个任意 字符
[若干字符 ] : 匹配 方括号中任意一个字符的一次出现
运行: [bozi@localhost 1_shell]$ ls * 2 3 sh_1.sh sh_2.sh [bozi@localhost 1_shell]$ ls sh_?.sh sh_1.sh sh_2.sh [bozi@localhost 1_shell]$ ls [s]h* sh_1.sh sh_2.sh
注意, Globbing 所匹配的文件名是由 Shell展开的 ,也就是说在参数还没传给程序之前已经展开
了 ,不是ls展开的
命令代换:
由反引号``括起来的也是一条命令 ,Shell先执行该命令 ,然后将输出结果立刻代换到当前命令行
中。
[bozi@localhost 1_shell]$ DATE=‘date‘ [bozi@localhost 1_shell]$ echo $DATE date [bozi@localhost 1_shell]$ DATE=`date` [bozi@localhost 1_shell]$ echo $DATE 2016年 08月 21日 星期日 11:05:13 CST
例如定义一个变量存放 date命令的输出 :
命令代换也可以用 $()表示 : $ DATE=$(date)
[bozi@localhost 1_shell]$ DATE=$(date) [bozi@localhost 1_shell]$ echo $DATE 2016年 08月 21日 星期日 11:05:56 CST
算术代换 :$(())
用于算术计算 ,$(())中的 Shell变量取值将转换成整数 ,例如 :
[bozi@localhost 1_shell]$ v=3 [bozi@localhost 1_shell]$ echo $((v+3)) 6
$(())中只能用+-*/ 和()运算符 ,并且只能做整数运算。
(( )) 中间支持c语言的写法
[bozi@localhost 1_shell]$ i=1;(( i++));echo $i 2 [bozi@localhost 1_shell]$ i=1;(( i+=5));echo $i 6 [bozi@localhost 1_shell]$ i=1;(( i>0));echo $? 0 [bozi@localhost 1_shell]$ i=1;(( i<0));echo $? 1
shell进度条小程序
代码:
#!/bin/bash function proc() { i=0; str=‘‘ arr=(‘|‘ ‘/‘ ‘-‘ ‘\\‘) index=0 while [ $i -le 100 ] #while ((i <= 100)) do printf "[%-100s][%d%%][%c]\r" "$str" "$i" "${arr[$index]}" #这里不用像c语言一样fflush刷新输出缓冲区 因为 printf是子进程执行 # 子进程退出自动刷新 str=${str}‘#‘ sleep 0.1 let i++ let index++ let index%=4 #((index%=4)) done printf "\n" } function main() { proc } main
运行:
[bozi@localhost 4_shell]$ sh proc.sh ######################################################################### ][74%][-]
读取文件数据 计算最大和最小值、平均值
代码:
#找 文件中的最大值和 最小值
max=0 min=0 count=0 sum=0 while read line do if [ "$count" -eq "0" ];then max=$line min=$line let count++ let sum+=$line continue fi [ "$max" -lt "$line" ] && max=$line [ "$min" -gt "$line" ] && min=$line let sum+=$line let count++ done <file echo $max echo $min echo "ibase=10 ;scale=2; $sum/$count" | bc
数据:
[bozi@localhost 4_shell]$ cat file 1 2 3 4 5 6 7 8 9
运行:
[bozi@localhost 4_shell]$ sh ./5_shell.sh 9 1 5.00
建议数字计算 用(()) 不用[ ] []对于空数据报错
如数据第四行空
file [bozi@localhost 4_shell]$ cat file 1 2 3 5 6 7 8 9
(())结果
if (( line < 9));then [bozi@localhost 4_shell]$ vim test.sh [bozi@localhost 4_shell]$ sh ./test.sh 1 2 3 5 6 7 8 error
[]结果 if [ "$line" -lt "9" ];then
[bozi@localhost 4_shell]$ sh ./test.sh 1 2 3 ./test.sh: line 11: ((: < 9 : syntax error: operand expected (error token is "< 9 ") error 5 6 7 8 error
数组
1 数组的定义
一对()表示数组 数组元素用 空格 符号作为分隔符
[bozi@localhost 4_shell]$ a=(1 2 3 4 5) [bozi@localhost 4_shell]$ echo $a 1 [bozi@localhost 4_shell]$ echo ${a[*]} 1 2 3 4 5 [bozi@localhost 4_shell]$ str=(‘q‘ "nihao" ‘hello‘) [bozi@localhost 4_shell]$ echo $str q [bozi@localhost 4_shell]$ echo ${str[@]} q nihao hello
2 数组的读取与赋值(下标从0开始)
赋值:
[bozi@localhost 4_shell]$ a[10]=10
读取:
[bozi@localhost 4_shell]$ echo ${a[*]} 1 2 3 4 5 10
[bozi@localhost 4_shell]$ echo ${a[@]} 1 2 3 4 5 10
得到长度:
得到整个数组长度
[bozi@localhost 4_shell]$ echo ${#a[*]} 6 [bozi@localhost 4_shell]$ echo ${#a[@]} 6
得到数组某个元素的长度
[bozi@localhost 4_shell]$ a=(1 2 3 4 5 10) [bozi@localhost 4_shell]$ echo ${a[@]} 1 2 3 4 5 10 [bozi@localhost 4_shell]$ echo ${#a[5]} 2 [bozi@localhost 4_shell]$ echo ${#a[0]} 1
删除:
[bozi@localhost 4_shell]$ echo ${a[@]} 1 2 3 4 5 10
#删除某个元素
[bozi@localhost 4_shell]$ unset a[2] [bozi@localhost 4_shell]$ echo ${a[@]} 1 2 4 5 10
#删除整个数组
[bozi@localhost 4_shell]$ unset a [bozi@localhost 4_shell]$ echo ${a[@]} [bozi@localhost 4_shell]$
3.特殊使用:
分片:
$[数组名{@或*]起始位置:长度} 从起始位置开始 切长度个元素
返回的是字符串 中间用空格隔开
所以如果加上"()" , 将的到切片的数组。
[bozi@localhost 4_shell]$ echo ${a[@]} 1 2 3 4 5 6 [bozi@localhost 4_shell]$ echo ${a[@]:0:3} 1 2 3 [bozi@localhost 4_shell]$ echo ${a[@]:2:3} 3 4 5 [bozi@localhost 4_shell]$ echo ${a[@]:2:5} 3 4 5 6 [bozi@localhost 4_shell]$ echo ${a[@]:1:5} 2 3 4 5 6
加上"()" , 将的到切片的数组。
[bozi@localhost 4_shell]$ echo ${a[@]:1:5} 2 3 4 5 6 [bozi@localhost 4_shell]$ newa=(${a[@]:1:5}) [bozi@localhost 4_shell]$ echo ${newa[@]} 2 3 4 5 6
替换:
调用方法是: ${数组名[@或*]/查找字符/替换字符} 该操作不会改变原先的内容, 如果需要修改, 可以像上面一样 加() 生成一个新的数组
[bozi@localhost 4_shell]$ a=(1 2 3 4 5 6) [bozi@localhost 4_shell]$ echo ${a[@]} 1 2 3 4 5 6 [bozi@localhost 4_shell]$ echo ${a[@]/3/100} 1 2 100 4 5 6 [bozi@localhost 4_shell]$ echo ${a[@]} 1 2 3 4 5 6
原内容 未改变
要改变原内容 加()
[bozi@localhost 4_shell]$ a=(${a[@]/3/100}) [bozi@localhost 4_shell]$ echo ${a[@]} 1 2 100 4 5 6 [bozi@localhost 4_shell]$ str=("nihao" hello) [bozi@localhost 4_shell]$ echo ${str[@]} nihao hello [bozi@localhost 4_shell]$ echo ${str[@]/ni/wo} wohao hello [bozi@localhost 4_shell]$ str=("nihao" "hello" "here") [bozi@localhost 4_shell]$ echo ${str[@]} nihao hello here [bozi@localhost 4_shell]$ echo ${str[@]/he/the} nihao thello there
遍历数组:
arr=(aaa bbb ccc ddd) num=${#arr[@]} for ((i = 0; i < num; i++)) { echo ${arr[i]} } [bozi@localhost 4_shell]$ sh arr.sh aaa bbb ccc ddd
特殊
arr=(aaa bbb ccc ddd) arr[50]="ffff" num=${#arr[*]} for ((i = 0; i < num; i++)) { echo ${arr[i]} }
结果 多了一个元素arr[50] 读也是读五个 只不过是从前向后读 没有读到arr[50] 读到空
这里${#arr[*]}和 ${#arr[@]}都是5
[bozi@localhost 4_shell]$ sh arr.sh aaa bbb ccc ddd [bozi@localhost 4_shell]$ cat arr.sh
下面这种方式解决读到空的问题 没有读到后面的有效数字
代码:
arr=(aaa bbb ccc ddd) arr[50]="ffff" num=${#arr[*]} for var in ${arr[*]} #for var in ${arr[@]} 这两个效果一样 都能访问到定义了的数据 { echo $var }
运行:
[bozi@localhost 4_shell]$ sh arr.sh aaa bbb ccc ddd ffff
[bozi@localhost 4_shell]$ for var in ${arr[*]}; do echo $var;let i++;done a b c hello [bozi@localhost 4_shell]$ arr[100]="iam100" [bozi@localhost 4_shell]$ for var in ${arr[*]}; do echo $var;let i++;done a b c hello iam100 [bozi@localhost 4_shell]$ [bozi@localhost 4_shell]$ for var in ${arr[*]}; do echo $var;let i++;done a b c hello [bozi@localhost 4_shell]$ arr[100]="iam100" [bozi@localhost 4_shell]$ for var in ${arr[*]}; do echo $var;let i++;done a b c hello iam100 [bozi@localhost 4_shell]$ for var in ${arr[@]}; do echo $var;let i++;done a b c hello iam100 [bozi@localhost 4_shell]$ i=0;while ((i < ${#arr[*]})); do echo ${arr[i]};let i++;done a b c hello [bozi@localhost 4_shell]$ i=0;while ((i < ${#arr[@]})); do echo ${arr[i]};let i++;done a b c hello [bozi@localhost 4_shell]$ ${arr[@]}; do echo $var;let i++;done a b c hello iam100 [bozi@localhost 4_shell]$ i=0;while ((i < ${#arr[*]})); do echo ${arr[i]};let i++;done a b c hello [bozi@localhost 4_shell]$ i=0;while ((i < ${#arr[@]})); do echo ${arr[i]};let i++;done a b c hello [bozi@localhost 4_shell]$
从这个 例子可以看出
for var in种方式访问的是 有效元素的个数
for ((i = 0; i < len;i++)) 是从前向后找 ,找len个就停止,后面隔着的有些有效的数据就没有输出
count=0; while [ $count -le 100] touch test${count};
数学运算(( ))中变量直接取得是 变量的值
v1=1
v2=2
((v3 = v1 + v2)) // (($v3 = $v1 + $v2)) 也可以
echo $(v3)
echo $(arr[*]) 显示所有的元素 (空的丢弃)
echo $(arr[@]) 显示所有的元素
echo $(#arr[@]) 显示 已经定义的元素的个数 如 arr
遍历数组
for i in $(arr[@])
do
echo $(arr[i])
done
单引号 双引号
单引号 对转义、特殊的变量 都不会 进行处理 原样输出
双引号 会处理
[bozi@localhost 1_shell]$ /bin/bash sh_1.sh
10
\$ \\ $myint \"
###############
$ \ 10 "
本文出自 “城市猎人” 博客,请务必保留此出处http://alick.blog.51cto.com/10786574/1841148