shell

Shell是一种用于Unix和类Unix操作系统上的脚本语言,常用于命令行交互和自动化任务。它包括注释、变量处理(如定义、赋值、只读)、字符串操作、数字处理、数组功能、逻辑表达式和控制结构(如if...then,for,while循环)。此外,文章还介绍了文件重定向、函数和文件操作等概念。
摘要由CSDN通过智能技术生成

shell

简介

Shell是一种脚本语言,通常用于在Unix和类Unix操作系统上进行命令行交互。它是用户与操作系统内核之间的接口,允许用户通过命令行或脚本文件来控制计算机上的操作。Shell程序通常用于执行复杂的任务,例如文件操作、网络通信、进程控制等。

Shell语言具有很高的灵活性,可以根据需要编写自定义脚本来自动化任务。Shell脚本通常包含一系列命令和流程控制语句,可以执行文件操作、程序运行、环境变量设置等任务。在Unix和类Unix操作系统中,常见的Shell包括Bash、Csh、Ksh等,它们都具有各自的特点和用法。Linux中默认使用bash。

运行

  • 文件开头需写#! /bin/bash,指明默认的脚本解释器。

  • 运行方式:

    1. 用解释器执行(可以没有权限):

      bash test.sh,test.sh是Shell脚本文件的名称。

    2. 作为可执行文件执行(必须要有权限):
      chmod +x test.sh,使脚本具有可执行权限。然后./test.sh直接运行。

    3. 在终端中执行Shell命令,并执行脚本:
      echo "echo Hello, World!" | sh

    其中第一种方法较常用。

语法

注释

  1. 单行注释(# 注释)
    在Shell脚本中,一行代码以 # 开头时,该行代码就被认为是注释,Shell 解释器会将这一行代码忽略。例如:

    #! /bin/bash
    
    # This is a comment
    echo "Hello World!"
    
  2. 多行注释
    在Shell脚本中,我们也可以使用一对 : << EOFEOF 来实现多行注释,其中一对EOF可以换成其他字符串,如: << qingqiu qingqiu

    #! /bin/bash
    
    : << suibian
    第一行注释
    第二行注释
    第三行注释
    suibian
    
    echo "Hello, World!"
    

变量

变量的命名规则

在Shell中,变量名遵循以下命名规则:

  • 变量名必须以字母或下划线开头。

  • 变量名中只能包含字母、数字和下划线。

  • 变量名不能以数字开头。

  • 变量名区分大小写。

  • 变量名和变量值之间不能有空格。

  • 如果变量值包含空格,需要使用引号将变量值括起来,例如name="qing qiu"

处理变量

在Shell中,变量可以用来存储字符串或数字等信息。可以通过定义变量、给变量赋值、使用变量等操作来进行变量处理。

  1. 定义变量
    定义变量有三种方法

    • name=qingqiu
    • name=“qingqiu”
    • name=‘qingqiu’

    其中不加引号和加双引号效果相同,支持变量替换和转义字符的解析,例如:

    name="qingqiu"
    echo "My name is $name"  # 输出:My name is qingqiu
    echo My name is $name  # 输出:My name is qingqiu
    

    而单引号不支持变量替换和转义字符的解析,在单引号中,所有的字符都会被当作普通字符处理,例如:

    name="qingqiu"
    echo 'My name is $name'  # 输出:My name is $name
    
  2. 给变量赋值

    可以使用=号来给变量赋值,等号两边不能有空格,否则会报错。

  3. 使用变量
    使用变量时需要在变量名前加上$,或者${}{}用于识别变量边界。例如:

    name=qingqiu
    echo $name  # 输出qingqiu
    echo ${name}  # 输出qingqiu
    echo $nameye  # 输出nameye
    echo ${name}ye  # 输出qingqiuye
    
  4. 只读变量
    readonly或者declare可以将变量变为只读,修改只读变量时会报错。

    name=qingqiu
    readonly name
    declare -r name  # 两种写法都可以
    name=a  # 会报错,因为此时name只读
    

    取消只读属性:

    unset -v name
    
  5. 删除变量

    unset可以删除变量。

    name=qingqiu
    unset name
    echo $name  # 输出空行
    

    要想删除只读变量,需要先取消只读属性,再用unset删除。

变量类型
局部变量与全局变量
  • 自定义变量(局部变量)
    子进程不能访问的变量。
  • 环境变量(全局变量)
    子进程可以访问的变量。

自定义变量与环境变量可以互相转换:
自定义变量→环境变量

name=qingqiu
export name  # 方法一
declare -x name  # 方法二

环境变量→自定义变量

export name=qingqiu  # 定义环境变量,只在当前bash有效
declare +x name  # 改为自定义变量
字符串

在shell中,字符串可以用单引号、双引号或不用引号来表示。单引号与双引号有区别,参考上述定义变量处。
字符串的操作

  • 获取字符串长度

    name="qingqiu"
    echo ${#name}  # 输出7
    
  • 提取子串

    name="qingqiu"
    echo ${name:0:4}  # 提取从0开始的4个字符,输出qing
    
数字

数字变量用来存储数字类型的数据。在shell中,数字变量可以是整数或浮点数。

数组

数组中可以存放多个不同类型的值,下标从0开始,初始化时不需要指明数组大小。

  1. 定义
  • 使用圆括号括起数组元素,并用空格隔开。例如:

    array=(666 qing "qiu" haha)
    
  • 使用花括号括起数组元素,并用逗号隔开。例如

    array={666, qing, "qiu", haha}
    
  • 直接定义数组中的某个元素的值:

    array[0]=666
    array[1]=qing
    array[2]="qiu"  # 只输出引号内字符串,建议使用"",以避免字符串含空格时出错
    array[3]=haha
    

直接定义某个元素的值时,下标可以不连续。例如:

array[0]=666
array[6]=qing
array[9]=“qiu”
array[999]=haha

echo ${#array[@]}  # 输出4
  1. 读取某个元素的值

    ${array[index]}  # 格式
    
    echo ${array[0]}  # 输出666
    echo ${array[1]}  # 输出qing
    echo ${array[2]}  # 输出qiu
    echo ${array[3]}  # 输出haha
    
  2. 读取整个数组

    ${array[@]}
    ${array[*]}  # 两种格式
    
    echo ${array[@]}
    echo ${array[*]}  #  两种写法均可
    

    在读取整个数组时,未定义的部分不会显示。例如:

    array[0]=666
    array[6]=qing
    array[9]=qiu
    array[999]=haha
    
    echo ${array[@]}  # 只会输出以上定义的四个值
    
  3. 数组长度

    ${#array[@]}
    ${#array[*]}  # 两种格式
    
    echo ${#array[@]}
    echo ${#array[*]}  # 两种写法均可
    
默认变量

默认变量是指在Shell中已经定义好的一些特殊变量,可以在Shell脚本中直接使用。一些常用的默认变量如下:

变量说明
$0当前脚本的文件名
$1 ~ $9传递给脚本或函数的参数。其中,$1表示第一个参数,$2表示第二个参数,以此类推。如果>9,需要用{}括起来,例如:${10}
$#传递给脚本或函数的参数个数
$*以一个单字符串显示所有向脚本传递的参数。参数之间用空格分隔
$@$*类似,但是每个参数都是独立的字符串,可以避免参数中含有空格等特殊字符的问题
$?上一个命令或者函数的退出状态exit code,0表示成功,非0表示失败
$$当前Shell进程的进程号
$(command)返回command这条命令的标准输出stdout(可嵌套)
command返回command这条命令的标准输出stdout(不可嵌套)

注意区分exit codestdout:exit code用于表示命令或程序的执行结果,而stdout则是命令或程序输出的内容。

expr命令

expr 表达式用于求表达式的值。

说明
  • 用空格隔开每一项。
  • 使用shell特定的字符需转义,或用反引号``(fn+~)括起来。
  • 对包含空格和其他特殊字符的字符串要用引号括起来。
  • expr会在stdout中输出结果。如果为逻辑关系表达式,则结果为真时,stdout输出1,否则输出0。1为真,0为假
  • expr同时会在exit code中输出结果。如果为逻辑关系表达式,则结果为真时,exit code为0,否则为1。0为真,1为假
字符串表达式
  • length string
    返回string的长度

  • index string charset
    charset中任意单个字符在string中最前面的字符位置,下标从1开始。如果string中完全不存在charset中的字符,则返回0。

    string="qingqiu"
    echo ${expr index "$string" ig}  # i在第2个位置出现,输出2
    echo ${expr index "$string" axx}  # 任一字符都没出现,输出0
    
  • substr string position length
    返回string字符串中从第position个位置开始,长度最大为length的子串。如果positionlength为0、负数、或非数值,则返回空字符串。

str="Hello World!"

echo `expr length "$str"`  # 输出12。反引号``表示直接获取命令的标准输出
echo `expr index "$str" ala`  # 输出3
echo `expr substr "$str" 2 3`  # 输出ell
整数表达式

expr支持普通算数操作,算术表达式优先级低于字符串表达式,高于逻辑关系表达式。

  • + -
    加减运算。两端参数回转换成整数,如果转换失败则报错。
  • * / %
    乘、除、取模运算,*需要转义。两端参数会转换为整数,如果转换失败则报错。
  • ()
    可以改变优先级,但使用时需要转义。
a=5
b=6
echo `expr $a + $b`  # 输出11
echo `expr $a / $b`  # 输出0
echo `expr \( $a + 1 \) \* \( $b + 4 \)`
逻辑表达式
  • |
    如果第一个参数非空且非0,则返回第一个参数的值,否则返回第二个参数的值,但要求第二个参数的值也是非空或非0,否则返回0。如果第一个参数是非空或非0时,不会计算第二个参数。
  • &
    如果两个参数都非空且非0,则返回第一个参数,否则返回0。如果第一个参为0或为空,则不会计算第二个参数。

|和&

  • < <= = == != >= >
    比较两端的参数,如果为true,则返回1,否则返回0。===是同义词。expr首先尝试将两端参数转换为整数,并做算术比较,如果转换失败,则按字符集排序规则做字符比较。

  • () 可以改变优先级,但需要转义。

read命令

read命令用于从标准输入中读取单行数据。当读到文件结束符时,exit code为1,否则为0。

参数说明
  • -p:后面可以接提示信息。
  • -t:后面跟秒数,定义输入字符的等待时间,超过等待时间后会自动忽略此命令。
read name
echo $name
read -p "Please input: " -t 30 name  # 读入name的值,等待时间为30s

echo命令

echo用于输出字符串。

  • 显示普通字符串

    echo "qingqiu"
    echo qingiu  # ""可以省略
    
  • 显示转义字符

    echo "\"qingqiu\""
    echo \"qingqiu\"  # “”带不带都可以,但不能带‘’
    
  • 原样输出字符

    name=qingqiu
    echo '$name\"'  # ‘’内的内容原样输出,输出$name\"
    
  • 显示变量

    name=qingqiu
    echo "I'm $name"  # 输出I'm qingqiu
    
  • 显示换行

    echo -e "hello\n"  # -e开启转义,\n表示hello后换行
    

    关于-e开启转义:在shell脚本中,可以使用-e选项来开启转义字符的解析,具体来说,-e选项可以用于以下几种情况:

    1. 转义字符的解析:当开启-e选项时,shell会将命令行中的转义字符进行解析,例如:\n会被解析成换行符,\t会被解析成制表符等。
    2. 强制文件名展开:在某些情况下,shell会对文件名进行展开,例如:ls *.txt,这个命令会将当前目录下所有的txt文件列出来。但是,如果有一个文件名包含了特殊字符,例如空格,那么这个文件名就无法被正确展开。此时可以使用-e选项来开启转义,例如:ls -e "my file.txt",这样可以强制shell将文件名中的空格转义,从而正确展开文件名。
    3. 解析echo命令中的转义字符:在echo命令中,可以使用转义字符来输出一些特殊字符,例如:\n可以输出换行符,\t可以输出制表符等。但是,在某些系统上,echo命令默认不解析转义字符,因此需要使用-e选项来开启转义,例如:echo -e "hello\nworld",这样可以正确输出换行符。

    需要注意的是,在使用-e选项时,要特别小心一些特殊字符的转义,例如\$符号,因为它会影响变量的展开。如果要输出\$符号,可以使用转义字符。

  • 显示不换行

    echo -e “hello\c”  # -e开启转义,\c表示hello后不换行
    
  • 显示结果定向至文件

    echo "qingqiu" > output.txt  # 将内容以覆盖方式输出到outpu.txt中
    
  • 显示命令执行结果

    echo `date`  # ``是反引号,输出现在的时间
    

printf命令

用于格式化输出,类似于C/C++中的printf函数。

test命令与判断符号[]

逻辑运算符
  • &&表示与,||表示或。
  • exit code为0时表示真,非零时表示假。

tips

  • |&expr定义的,||&&是bash自带的。

  • ||&&可以判断表达式是否为真,但根据短路原则,也常常用于实现if的作用。
    短路原则:

    expr1 && expr2:当expr1为假时,直接忽略expr2

    expr1 || expr2:当expr1为真时,直接忽略expr2

    # 假设当前目录下有一个文件test.sh
    
    test -e test.sh && echo "exist" || echo "not exist"  # 若test.sh存在,输出exist,否则输出not exist
    
test命令

test命令用于判断文件类型以及比较变量,用exit code返回结果,0为真,非0为假。(exprstdout返回结果,1表示真,0表示假)

  • 判断文件类型

    test -e filename  # 判断文件是否存在
    test -f filename  # 判断是否为文件
    test -d filename  # 判断是否为目录
    
  • 判断文件权限

    test -r  # 判断文件是否可读
    test -w  # 判断文件是否可写
    test -x  # 判断文件是否可执行
    test -s  # 判断是否为空文件
    
  • 比较整数

    test $a -eq $b  # 判断a是否等于b
    test $a -ne $b  # 判断a是否不等于b
    test $a -gt $b  # 判断a是否大于b
    test $a -lt $b  # 判断a是否小于b
    test $a -ge $b  # 判断a是否大于等于b
    test $a -le $b  # 判断a是否小于等于b
    
  • 比较字符串

    test -z string  # 判断string是否为空,若为空返回true
    test -n string  # 判断string是否非空,若非空返回true(-n可以省略)
    test str1 == str2  # 判断str1是否等于str2
    test str1 != str2  # 判断str1是否不等于str2
    
  • 多重条件判定

    test -r filename -a -x filename  # (and) 两个条件是否同时成立
    test -r filename -o -x filename  # (or) 两个条件是否至少成立一个
    test ! -x file  # (非) 取反。file不可执行时返回true
    
判断符号[](命令)

[]test用法几乎一模一样,更常用于if语句中。另外[[]][]的加强版,支持的特性更多。

tips:[]中只有[是命令,]可以理解为一个参数。在使用时二者缺一不可。

注意:

  • []是一个命令,里面的每一项都要用空格隔开
  • 中括号内的变量,最好用双引号括起来
  • 中括号内的常数,最好用单或双引号括起来

判断语句

if…then

类似于C/C++中的if-else语句。

  • 单层if

    # 格式
    if 表达式  # 判断的是表达式的exit code
              # 注意if后应该接命令,而不能是一个值
    then
    	语句1
    	...
    fi  
    
    
    # 示例
    a=3
    b=4
    if [ "$a" -lt "$b" ] && [ "$a" -gt 2 ]
    then
    	echo ${a}在范围内
    fi  # 输出3在范围内
    
  • 单层if-else

    # 格式
    if 表达式
    then
    	语句1
    	...
    else
    	语句1
    	...
    fi
    
    
    # 示例
    a=3
    b=4
    if [ "$a" -lt "$b" ]
    then
    	echo ${a}小于${b}
    else
    	echo ${a}不小于${b}
    fi  # 输出3小于4
    
  • 多层if-elif-elif-else

    # 格式
    if 表达式
    then
        语句1
        ...
    elif condition
    then
        语句1
        ...
    elif condition
    then
        语句1
    else
        语句1
        ...
    fi
    
    
    # 示例
    a=4
    if [ $a -eq 1 ]
    then
        echo ${a}等于1
    elif [ $a -eq 2 ]
    then
        echo ${a}等于2
    elif [ $a -eq 3 ]
    then
        echo ${a}等于3
    else
        echo 其他
    fi  # 输出其他
    
case…esac

类似于C/C++中的switch语句。

# 格式
case $变量名 in
	值1)
		语句1
		...
		;;  # 类似于C/C++中的break
	值2)
		语句1
		...
		;;
	*)  # 类似于C/C++中的default(匹配所有值)
		语句1
		...
		;;
esac


# 示例
a=4
case $a in
    1)
        echo ${a}等于1
        ;;  
    2)
        echo ${a}等于2
        ;;  
    3)                                                
        echo ${a}等于3
        ;;  
    *)
        echo 其他
        ;;  
esac  # 输出其他

循环语句

for…in…do…done
# 格式
for var in val1 val2 val3
do
	语句1
	...
done


# 示例1
for i in q i n g
do
	echo $i
done  # 每行输出一个元素

# 示例2
for file in `ls`
do
	echo $file
done  # 逐行输出当前路径下所有文件名

# 示例3
for i in $(seq 1 10)  # seq命令返回一个序列
do
	echo $i
done  # 输出1-10

# 示例4
for i in {a..z}  # bash内嵌的范围写法
do
	echo $i
done  # 逐行输出a,b,c,d,...,z
for ((…;…;…)) do…done

类似于C/C++中的for循环。

# 格式
for ((赋初值; 判断; 修改变量))
do
	语句1
	...
done


# 示例
for((i=1; i<=10; i++))
do
	echo $i
done  # 输出1-10
while…do…done
# 格式
while condition
do
	语句1
	...
done


# 示例1
i=0
while [ $i -lt 10 ]
do
	echo $i
	i=$(expr $i + 1)  # 可以写成((i++))
done


# 示例2
while read name
do
	echo $name  # 读到结束符时,输出读取的字符串
done
until…do…done

条件为真时结束。

# 格式
until condition
do
	语句1
	...
done


# 示例
until [ "${word}" == "yes" ] || [ "${word}" == "YES" ]  # 注意有两个[],用||隔开
do
	read -p "Please input yes/YES to stop:" word
done  # 输入yes/YES时结束,否则一直等待读入
跳出循环
  • break命令

    跳出当前这层循环,break不能跳出case语句,case中的跳出循环用;;

    while read name
    do
        for ((i=1;i<=10;i++))
        do
            case $i in
                8)
                    break
                    ;;
                *)
                    echo $i
                    ;;
            esac
        done
    done  # 每读入非EOF的字符串,会输出一遍1-7
    
  • continue命令
    跳出当前这次循环。

    for ((i=1;i<=10;i++))
    do
        if [ `expr $i % 2` -eq 0 ]
        then
            continue
        fi
        echo $i
    done  # 输出1-10中所有奇数
    
死循环处理
  1. 使用top命令找到该进程的PID。
  2. 输入kill -9 PID关掉此进程。

函数

bash中的函数类似于C/C++中的函数,但return的返回值与C/C++不同,返回的是exit code,取值为0-255,0表示正常结束。

如果想获取函数的输出结果,可以通过echo输出到stdout中,然后通过$(function_name)来获取stdout中的结果。

函数的return值可以通过$?来获取。

func()
{
    name=qingqiu
    echo "Hello $name"
    return 9  # 不写return时默认return0
}

func  # 调用时不需要加()

output=$(func)  # 获取标准输出
ret=$?  # 获取退出状态
echo "output = $output"
echo "return = $ret"

exit命令

  • exit命令用来退出当前shell进程,并返回一个退出状态;使用$?可以接收这个退出状态。

  • exit命令可以接受一个整数值作为参数,代表退出状态。如果不指定,默认状态值是 0。

  • exit退出状态只能是一个介于 0~255 之间的整数,其中只有 0 表示成功,其它值都表示失败。

文件重定向

每个进程默认打开3个文件:

  • stdin:标准输入,从命令行读取数据,文件描述符为0
  • stdout:标准输出,向命令行输出数据,文件描述符为1
  • stderr:标准错误输出,向命令行输出数据,文件描述符为2

可以用文件重定向将这三个文件重定向到其他文件中。

命令说明
command > file将stdout重定向到file中(覆盖内容)
command < file将stdin重定向到file中
command >> file将stdout以追加方式重定向到file中
command n> file将文件描述符n重定向到file中
command n>> file将文件描述符n以追加方式重定向到file中

引入外部脚本

类似于C/C++中的include操作,bash也可以引入其他文件中的代码。

语法格式:

. filename  # .和filename之间有一个空格
source filename  # 两种方法都可以
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值