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变量值)

特殊变量:

$?: 命令的状态结果;

$#: 传递给脚本或函数的参数的个数;

$*和[email protected]: 引用传递给脚本或函数的参数列表;

算术运算:

+, -, *, /, %(求余), **(乘方)

-=, *=, /=, %=,++,--

例子: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

返回结果:

[[email protected] ~]# bash test10.sh
3

[[email protected] ~]#

由此可以看出$?能够返回函数的结果,而复制的$v变量为空。

对于$?只支持0-255返回值,我们再来一个实例

#!/bin/bash

function sum() {
        return $(($1+$2))
}

sum 100 200

echo $?

返回结果:

[[email protected] ~]# bash test10.sh
44
[[email protected] ~]#

这个结果一看怎么可能为44.

为解决这个情况,我又将脚本改了下:

#!/bin/bash

declare v
function sum() {
        v=$(($1+$2))
}

sum 100 200

echo $v

我们再来看看返回结果:

[[email protected] ~]# bash test10.sh
300
[[email protected] ~]#

结果正确了,我的思路是申请了一个全局变量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[@]}

返回结果:

[[email protected] ~]# bash test10.sh
31870 27033 25714 22587 21793 12488 11529 7180 4051 1751
[[email protected] ~]#

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}"
时间: 2024-12-25 05:59:07

linux shell详解的相关文章

Linux 目录详解 树状目录结构图

1.树状目录结构图 2./目录 目录 描述 / 第一层次结构的根.整个文件系统层次结构的根目录. /bin/ 需要在单用户模式可用的必要命令(可执行文件):面向所有用户,例如:cat.ls.cp,和/usr/bin类似. /boot/ 引导程序文件,例如:kernel.initrd:时常是一个单独的分区[6] /dev/ 必要设备, 例如:, /dev/null. /etc/ 特定主机,系统范围内的配置文件. 关于这个名称目前有争议.在贝尔实验室关于UNIX实现文档的早期版本中,/etc 被称为

Gentoo Linux安装详解--根据官方WiKi整理

1. 前期准备 远程登录: 开启ssh服务: /etc/init.d/sshd start 设置密码: passwd 以便使用putty.ssh client远程登录上传stage等(有时在线下载很慢,而局域网上传很快) 准备磁盘: 分区: fdisk /dev/sda /dev/sda1 : /boot 100M(32-100M) 设启动笔记-a/dev/sda2 : / 20G/dev/sda3 : /home 20G/dev/sda5 : /swap 1G (内存< 512 MB,分区分配

Gentoo Linux安装详解

1. 前期准备 远程登录: 开启ssh服务: /etc/init.d/sshd start 设置密码: passwd 以便使用putty.ssh client远程登录上传stage等(有时在线下载很慢,而局域网上传很快) 准备磁盘: 分区: fdisk /dev/sda /dev/sda1 : /boot 100M(32-100M) 设启动笔记-a/dev/sda2 : / 20G/dev/sda3 : /home 20G/dev/sda5 : /swap 1G (内存< 512 MB,分区分配

Linux命令详解之—more命令

Linux more命令同cat命令一样,多用来查看文件内容,本文就为大家介绍下Linux more命令的用法. 更多Linux命令详情请看:Linux命令速查手册 Linux的more命令类似 cat命令 ,不过more命令以一页一页的形式显示,更方便使用者逐页阅读. 按空白键(space)就往下一页显示,按 b 键就会往回(back)一页显示,输入/+字符串可以搜索字符串(与vi搜索类似). 一.Linux more命令语法 more命令的语法格式如下: more [-dlfpcsu] [-

Linux命令详解--文件与目录查找

一·文件搜索 which:用来查找命令的绝对路径-- 显示shell命令的绝对路径-- 仅仅会在PATH变量中搜索要查找的命令-- 搜索时先查找别名,然后从PATH中查找1.查看用户的PATH变量:命令的搜索路径# echo $PATH/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/root/bin command not found可能原因:1)敲错了2)命令没有安装3)命令

shell详解

============================================================================1.shell详解:shell是基于c语言的基础上编写的程序,是用户与Linux内核之间沟通的桥梁:shell既是一种命令语言,又是一种程序语言.shell是只一种应用程序,这个应用程序提供一个界面,用户通过这个界面访问操作系统内核的服务. 2.shell脚本:是一种为shell编写的脚本程序:shell脚本就是将各种命令通过逻辑语句组合而成的程

Linux Ptrace 详解

转 https://blog.csdn.net/u012417380/article/details/60470075 Linux Ptrace 详解 2017年03月05日 18:59:58 阅读数:6331 一.系统调用 操作系统提供一系列系统调用函数来为应用程序提供服务.关于系统调用的详细相关知识,可以查看<<程序员的自我修养>第十二章. 对于x86操作系统来说,用中断命令"int 0x80"来进行系统调用,系统调用前,需要将系统调用号放入到%EAX寄存器中,将

Linux信号详解

Linux信号详解 一 信号的种类 可靠信号与不可靠信号, 实时信号与非实时信号 可靠信号就是实时信号, 那些从UNIX系统继承过来的信号都是非可靠信号, 表现在信号 不支持排队,信号可能会丢失, 比如发送多次相同的信号, 进程只能收到一次. 信号值小于 SIGRTMIN的都是非可靠信号. 非可靠信号就是非实时信号, 后来, Linux改进了信号机制, 增加了32种新的信号, 这些信 号都是可靠信号, 表现在信号支持排队, 不会丢失, 发多少次, 就可以收到多少次. 信号值 位于 [SIGRTM

linux awk详解与应用

文章来自于本人个人博客: linux awk详解与应用 1.awk awk是一个强大的文本分析工具,它可以通过分析文本来生成一个数据报告.它的原理就是读取每行的输入,然后按照分隔符切分(默认是空格),再进行定制计算. awk '{print $1}' /etc/passwd   #打印出passwd文件的所有行的第一列 这是awk的基础语法,在awk中$n代表列数,即$1--第一列,$2---第二列....,但是$0代表整行 接下来我们按照指定的分隔符打印数据: awk -F ':' '{pri