标签:linux shell
shell工作原理
Linux系统提供给用户的最重要的系统程序是Shell命令语言解释程序。它不属于内核部分,而是在核心之外,以用户态方式运行。其基本功能是解释并执行用户打入的各种命令,实现用户与Linux核心的接口。系统初启后,核心为每个终端用户建立一个进程去执行Shell解释程序。它的执行过程基本上按如下步骤: (1)读取用户由键盘输入的命令行。 (2)分析命令,以命令名作为文件名,并将其它参数改造为系统调用execve( )内部处理所要求的形式。 (3)终端进程调用fork( )建立一个子进程。 (4)终端进程本身用系统调用wait4( )来等待子进程完成(如果是后台命令,则不等待)。当子进程运行时调用execve( ),子进程根据文件名(即命令名)到目录中查找有关文件(这是命令解释程序构成的文件),将它调入内存,执行这个程序(解释这条命令)。 (5)如果命令末尾有&号(后台命令符号),则终端进程不用系统调用wait4( )等待,立即发提示符,让用户输入下一个命令,转⑴。如果命令末尾没有&号,则终端进程要一直等待,当子进程(即运行命令的进程)完成处理后终止,向父进程(终端进程)报告,此时终端进程醒来,在做必要的判别等工作后,终端进程发提示符,让用户输入新的命令,重复上述处理过程。
shell语法
变量赋值:
name=value
语法注意:=左右千万不能有空格,不然bash会报错,这个和其它语言不一样,比如javascript,php之类的,之前经常容易犯这个错误,写习惯了别的语言。
变量引用:
弱引用: "", 其内部的变量引用会被替换为变量值;
强引用:‘‘,其变量的变量引用会保持原有字符;
命令引用:`COMMAND`, $(COMMAND),引用命令的执行结果;
声明为整型:
declare -i name=3
let name=2
运行脚本
事实上是运行一个bash进程,此进程负责从脚本文件中读取一个执行逻辑,而后由bash进程负责解析并运行此逻辑;
启动脚本:
(1) # bash /PATH/TO/SCRIPT_FILE
(2) 给shell脚本一个执行权限,
# ./PATH/TO/SCRIPT_FILE
条件测试:
test EXPRESSION
[ EXPRESSION ]
语法注意:[的右边和]的左边一定要有空格,和赋值刚好相反
整数测试:隐含着做数值大小比较,所以不要给变量引用加引用;
$A -gt $B:是否大于;是则为“真”,否则为“假”;
$A -ge $B: 是否大于等于;
$A -lt $B:是否小于;
$A -le $B: 是否小于等于;
$A -eq $B: 是否等于;
$A -ne $B:是否不等于;
字符串测试:ASCII数值越大,字符比较时其值越大;
"$A" > "$B":是否大于;
"$A" < "$B":是否小于;
"$A" == "$B":是否等于;
"$A" =~ PATTERN:模式匹配;
"$A" != "$B":是否不等于;
-z "$A":是否为空;空则为“真”,否则为“假”
-n "$A":是否不空;不空则“真”,空则为“假”
注意:引用字符串变量$A和$B比较时,变量$A和$B左右两侧都需要加"",这点有和别的语言不一样,像php判断if ($A == $B)即可,而bash必须为if [ "$A" == "$B" ],这个错误之前经常犯
文件测试:测试文件的存在性以及属性;
-e $file: 是否存在;存在则为“真”,否则为“假”;
-a $file: 同上;
-f $file:文件是否存在且为普通文件;
-d $file:文件是否存在且为目录;
-h $file:是否存在且为符号链接文件;
-L $file: 同上
-b $file:是否存在且为块设备文件;
-c $file:是否存在且为字符设备文件;
-S $file:是否存在且为套接字文件;
-p $file: 是否存在且为管道文件;
-r $file: 当前用户对文件是否拥有读权限;
-w $file:当前用户对文件是否拥有写权限;
-x $file:当前用户对文件是否拥有执行权限;
-u $file:文件是否拥有SUID权限;
-g $file:文件是否拥有SGID权限;
-k $file:文件是否拥有sticky权限;
-O $file: 当前用户是否为指定文件的属主;
-G $file: 当前用户是否为指定文件的属组;
双目操作符:
$file1 -nt $file2: file1是否新于file2, file1的最近一次的修改时间戳是否晚于file2的;
$file1 -ot $file2: file1是否旧于file2, file1的最近一次的修改时间戳是否早于file2的;
$file1 -ef $file2:file1与file2是否指向了同一个inode;测试二者是否为同一个文件的硬链接;
组合测试:
与:[ CONDITION1 -a CONDITION2 ] 例子:[ -n "$str" -a "$str" == "haha200142323" ]
或:[ CONDITION1 -o CONDITION2 ]
非:[ ! CONDITION1 ]
多个语句连环执行:
与:COMMAND1 && COMMAND2 如果COMMAND1执行成功,则执行COMMAND2
或:COMMAND1 || COMMAND2 如果COMMAND1执行不成功,则执行COMMAND2
非: ! COMMEND
特殊设备:
/dev/null: 空,bit buckets,吞下所有数据,并直接丢弃;
/dev/zero:吐出一堆0;
位置参数变量:
#bash test10.sh($0变量值) 123($1变量值) 333($2变量值)
特殊变量:
$?: 命令的状态结果;
$#: 传递给脚本或函数的参数的个数;
$*和$@: 引用传递给脚本或函数的参数列表;
算术运算:
+, -, *, /, %(求余), **(乘方)
-=, *=, /=, %=,++,--
例子:let count++,let count+=1,let count++
语法:
1.$[$A+$B], 例子:echo $[1+4],输出5
2.$(($A+$B)),例子:echo $((1+4)),输出5,我也经常用该方式运行复杂运算。比如(1+4)*5,用该方式为$(((1+4)*5)),输出25
3.let c=$a+$b
4.$(expr $a + $b) 注意:+左右两边一定都要有空格
流程控制语句
if语句
if [ CONDITION1 ]; then 片段1 elif [CONDITION2]; then 片段2 else 片段3 fi
case语句
case $VARIABLE in PATTERN1) 语句1 ;; PATTERN2) 语句2 ;; PATTERN3) 语句3 ;; *) 语句4 ;; esac
注意PATTERN1,PATTERN2,PATTERN3可使用glob模式的通配符:
*: 任意长度的任意字符;
?: 任意单个字符;
[]: 指定范围内的任意单个字符;
a|b: 多选1;
for语句
方式一:
for i in $var; do echo $i done
方式二:
cnt=100 for (( i=1;i<=$cnt;i++ )); do echo $i done
while语句
方式一:
while [ $n -lt 100 ]; do echo $n done
方式二:
while read line; then echo $line done < /etc/passwd
该方式可以取文件中的每一行($line即为每行的内容)
until语句
i=0 until [ $i -lt 100 ]; do echo $i let i++ done
函数
function fname() { 语句块 }
这里我使用其他编程语言通用的方式把
函数返回的内容只可以用$?返回,但貌似只支持0-255的返回值,而且不能用=将函数返回结果赋值给变量,比如:
#!/bin/bash function sum() { return $(($1+$2)) } sum 1 2 echo $? v=$(sum 1 2) echo $v
返回结果:
[root@localhost ~]# bash test10.sh 3 [root@localhost ~]#
由此可以看出$?能够返回函数的结果,而复制的$v变量为空。
对于$?只支持0-255返回值,我们再来一个实例
#!/bin/bash function sum() { return $(($1+$2)) } sum 100 200 echo $?
返回结果:
[root@localhost ~]# bash test10.sh 44 [root@localhost ~]#
这个结果一看怎么可能为44.
为解决这个情况,我又将脚本改了下:
#!/bin/bash declare v function sum() { v=$(($1+$2)) } sum 100 200 echo $v
我们再来看看返回结果:
[root@localhost ~]# bash test10.sh 300 [root@localhost ~]#
结果正确了,我的思路是申请了一个全局变量v,再在函数中将函数结果赋值给v。
吐槽:bash对于这块实在太坑爹了,有没有更好的方法将函数返回值赋值个变量,欢迎大神告诉我一下,哈哈!
数组
申明变量:
传统数组:索引为数字,从0开始编号;
declare -a ARRAY_NAME
关联数组:索引可以自定义,可以使用任意字符串做索引;
declare -A ARRAY_NAME
支持稀疏格式
赋值:
一次只赋值一个元素
array[index]=value
一次赋值全部元素
array=("val1" "val2" ...)
指定索引进行赋值
array=([0]="val1" [3]="val2")
read -a array
获取数组长度:
${#a[@]}或者${#a[*]}
得到整个数组:
${a[@]}或者${a[*]}
读取数组指定位置:
${a[index]}
删除数组指定位置:
unset a[index]
切分数组:
${a[@]:起始位置:长度}
替换数组:
${a[@]/查找字符/替换字符}
循环数组
#!/bin/bash a=(1 2 30 4 5) for i in ${a[@]}; do echo $i done
小练习:利用bash生成10个随机数值,保存于数组中;要此些数组从大到小降序排列;
#!/bin/bash declare -a a declare -i sum=10 for (( i=0;i<$sum;i++ )); do a[$i]=$RANDOM done count=${#a[@]} for (( i=0;i<$count;i++ )); do for (( j=i+1;j<$count;j++ )); do if [ ${a[i]} -lt ${a[j]} ]; then temp=${a[i]} a[i]=${a[j]} a[j]=$temp fi done done echo ${a[@]}
返回结果:
[root@localhost ~]# bash test10.sh 31870 27033 25714 22587 21793 12488 11529 7180 4051 1751 [root@localhost ~]#
read命令
作用:和用户交互输入数值到一个变量中去
-a:上面已经提到,读一个数组
-p:提示用户输入变量之前输出的字符
-t:用户输入变量的超时时间
实战演练
如果某路径不存在,则将其创建为目录;否则显示其存在,并显示内容类型;
#!/bin/bash file=$1 if [ -z "$file" ]; then echo "params error!"; exit 1 fi if [ ! -e "$file" ]; then mkdir -p $file else echo "$file is exist.." file $file fi
2.写一个脚本,完成如下功能;判断给定的两个数值,孰大孰小;给定数值的方法:脚本参数,命令交互;
#!/bin/bash read -p ‘please input two integer value:‘ a b if [ -z "$a" ]; then echo ‘please input a value‘ exit 1 fi if [ -z "$b" ]; then echo ‘please input two params‘ fi if [ $a -eq $b ]; then echo "${a} is equal to ${b}" elif [ $a -gt $b ]; then echo "${a} is greater than ${b}" else echo "${a} is smaller than ${b}" fi
3.求100以内所有奇数之和(至少用3种方法)
#/bin/bash declare -i sum=0 declare -i i=1 while [ $i -lt 100 ]; do let sum+=$i let i+=2 done echo $sum
4.写一个脚本实现如下功能:
(1) 传递两个文本文件路径给脚本;
(2) 显示两个文件中空白行数较多的文件及其空白行的个数;
(3) 显示两个文件中总行数较多的文件及其总行数;
#!/bin/bash read -p ‘please input two file path:‘ file1 file2 if [ -z "${file1}" ]; then echo "file1 param is empty.." exit 1 fi if [ ! -f "$file1" ]; then echo "$file1 is not a file" exit 2 fi if [ -z "$file2" ]; then echo ‘file2 param is empty..‘ exit 3 fi if [ ! -f "$file2" ]; then echo "${file2} is not a file" exit 4 fi kb_num1=$(grep -E ‘^$‘ $file1 | wc -l | cut -d‘ ‘ -f1) kb_num2=$(grep -E ‘^$‘ $file2 | wc -l | cut -d‘ ‘ -f1) total_num1=$(wc -l $file1 | cut -d‘ ‘ -f1) total_num2=$(wc -l $file2 | cut -d‘ ‘ -f1) if [ $kb_num1 -gt $kb_num2 ]; then echo "the more space lines is ${file1}, space lines is ${kb_num1}" elif [ $kb_num1 -lt $kb_num2 ]; then echo "the more space lines is ${file2}, space lines is ${kb_num2}" else echo "${file1} space lines is equal to ${file2}. and the space lines is ${kb_num1}"; fi if [ $total_num1 -gt $total_num2 ]; then echo "the more total lines is ${file1}, total lines is ${total_num1}" elif [ $kb_num1 -lt $kb_num2 ]; then echo "the more total lines is ${file2}, total lines is ${total_num2}" else echo "${file1} total lines is equal to ${file2}. and the total lines is ${total_num1}"; fi
5.写一个脚本
(1) 提示用户输入一个字符串;
(2) 判断:
如果输入的是quit,则退出脚本;
否则,则显示其输入的字符串内容;
#!/bin/bash read -p ‘please input a string:‘ str if [ -z "$str" ]; then echo ‘the string can not be empty‘ exit 1 fi if [ "$str" == "quit" ]; then exit 0 else echo $str fi
6.写一个脚本,打印2^n表;n等于一个用户输入的值
#!/bin/bash read -p "please input a integer value:" -n1 n for (( i=0;i<=$n;i++ )); do let cv=2**$i echo "2^${i}=${cv}" done
7.写一个脚本,写这么几个函数:
函数1、实现给定的两个数值的之和;
函数2、取给定两个数值的最大公约数;
函数3、取给定两个数值的最小公倍数;关于函数的选定、两个数值的大小都将通过交互式输入来提供。
#!/bin/bash declare -i totalvalue declare -i my declare -i mb function add() { totalvalue=$(($1+$2)) } #求最大公约数 function maxyin() { declare -i m if [ $1 > $2 ]; then m=$2 else m=$1 fi while [ $m -gt 1 ]; do if [ $(($1 % $m)) -eq 0 ] && [ $(($2 % $m)) -eq 0 ]; then my=$m break; fi let m-- done my=1 } #求最小公倍数 function minbei() { declare -i n if [ $1 > $2 ]; then n=$1 else n=$2 fi while true; do if [ $(($n % $1)) -eq 0 ] && [ $(($n % $2)) -eq 0 ]; then mb=$n break; fi let n++ done } read -p "please input two integer value to calculate the sum:" i1 j1 add $i1 $j1 echo "${i1}+${j1}=${totalvalue}" read -p "please input two integer value to get max gongyueshu:" i2 j2 maxyin $i2 $j2 echo "${i2} with ${j2} the max gongyueshu is ${my}" read -p "please input two integer value to get min beishu:" i3 j3 minbei $i3 $j3 echo "${i3} with ${j3} the min beishu is ${mb}"
本文出自 “风之韵” 博客,请务必保留此出处http://chinalx1.blog.51cto.com/2334265/1698448
标签:linux shell
原文地址:http://chinalx1.blog.51cto.com/2334265/1698448