码迷,mamicode.com
首页 > 系统相关 > 详细

linux shell详解

时间:2015-09-27 06:37:57      阅读:195      评论:0      收藏:0      [点我收藏+]

标签: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:用户输入变量的超时时间

    


实战演练

  1. 如果某路径不存在,则将其创建为目录;否则显示其存在,并显示内容类型;  

#!/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详解

标签:linux shell

原文地址:http://chinalx1.blog.51cto.com/2334265/1698448

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!