shell基础

1. 常用操作

1.1 shell脚本的执行方式

  • . a.sh : 以当前shell解析器来执行脚本(当前shell来执行,即没有开启子程序)
  • source a.sh : 以当前shell解析器来执行脚本(当前shell来执行,即没有开启子程序)
  • ./a.sh : 以文件#!指定的解析器来执行脚本(子shell来执行,所以共享系统变量,但不共享环境变量)
  • bash a.sh : 以指定的bash解析器来执行脚本
    • bash -vx a.sh : 打印调试信息

1.2 shell终端是否登录状态

  • echo $0

    • 若结果为 -bash ,则为登录状态
    • 若结果为 bash,则为未登录状态
  • bash : 在终端中执行该命令则会切换到未登录状态

  • su user1 : 以未登录方式切换用户

  • su - user1 : 以登录方式切换用户

  • 登录shell

    • 登录 shell 需要输入账户密码,会初始化全局配置
  • 非登录 shell

    • 通过命令bash打开新 shell 或 su user,一般不需要密码,会继承父 shell 的环境,会执行~/.bashrc等非登录配置文件

1.3 shell终端启动时脚本文件执行顺序

  1. /etc/profile
    • 系统级登录状态全局配置。
    • 开机时或切换用户登录时执行一次,且只执行一次。
    • 针对所有类型的 shell 终端有效
    • 里面默认会调用/etc/profile.d/*.sh 脚本。
  2. $HOME/.bash_profile
    • 用户级登录状态私有配置,可以覆盖全局配置。
    • 也是用户登录时执行一次,且只执行一次
    • 只针对 bash 类型的 shell 终端有效
    • bash类型终端,如果发现有这个配置文件,会执行这个文件,然后默认会忽略.profile文件。
  3. $HOME/.profile
    • 用户级登录状态私有配置,可以覆盖全局配置
    • 也是用户登录时执行一次
    • 针对所有类型的 shell 终端有效
  4. $HOME/.bashrc
    - 用户私有配置。
    - 针对 bash 终端有效,打开新的 bash 会执行一次
    - 针对 Bash shell 的非登录、交互式 shell
  5. /etc/bashrc
    • 全局配置
    • 针对bash终端有效,非登录时打开终端会执行一次
    • 在ubantu中是 /etc/bash.bashrc
  6. $HOME/.bash_logout 退出shell时会执行该脚本

以 su - user1 切换账户会执行以下脚本文件

  • /etc/profile 全局配置
    • /etc/profile.d/*.sh
  • $HOME/.bash_profile 私有配置

以 su user1 切换账户会执行以下脚本文件

  • /etc/bashrc 全局配置
  • $HOME/.bahsrc 私有配置

1.3.1 login shell 与no-login shell

  • login shell的必要条件时至少需要输入密码(但并不是输入密码的都是登录shell 如 su ljs)
  • 一般来说login shell只会读取这两个配置脚本 (只不过这两个脚本里有读了其他脚本)
    • /etc/profile: 系统的整体设置,最好不要修改这个文件
    • ~/.bash_profile~/.bash_login~/.profile:用户的个人设置
  • 一般来说login shell执行的脚本默认情况如下
    • /etc/profile
      • /etc/profile.d/*.sh
    • ~/.bash_profile
      - ~/.bashrc
      - /etc/bashrc (这个是Red Hat 系统特有)
  • 一般来说no-login shell只会读取 和/etc/bashrc~/.bashrc而已

1.3.2 /etc/profle

  • 它本身是一段shell脚本
  • 会根据用户去设置一些信息如
    • 根据用户账号是否是超级管理员确定$PATH变量是否包含sbin的系统指令目录
    • 根据用户账号设置USER变量
    • 根据用户设置umask(root默认022,一般用户为002)
  • 会去执行/etc/profile.d/*sh脚本
    • /etc/profile.d/lang.sh 会读取/etc/locale.conf配置
    • /etc/profile.d/bash_completion.sh 实现了命令补全

1.3.3 ~/.bash_profile

  • ~/.bash_profile~/.bash_login~/.profile 三个脚本在login shell中只会读取其中一个优先级是针对与 bash 类型的终端,他们都是用户级别的私有配置
    1. ~/.bash_profile
    2. ~/.bash_login
    3. ~/.profile
  • 这里面一般会对PATH变量进行补充,添加一下针对于当前用户的一些可执行命令

1.3.4 ~/.bashrc

  • 一般我们会在这里做一些个人设置,如给命令设置别名
  • 默认会调用/etc/bashrc, 而/etc/bashrc 一般做了以下工作:(/etc/bashrc是Red Hat系列特有)
    • 依据不同的uid规范出umask的值
    • 依据不同的uid规范出提示字符 (PS1变量)
      - 对于no-login shell, 会调用/etc/profile.d/*.sh

1.3.5 ~/.bash_logout

  • 在登出bash后,系统再帮我们做完什么动作后才离开。

1.4 一些快捷键

  • Ctrl+D :输入结束(EOF)
  • Ctrl+R :模糊搜索一个历史命令
  • Ctrl+A :光标移动到行首
  • Ctrl+E :光标移动到行尾
  • Ctrl+U :删除行首到光标处的字符
  • Ctrl+K : 删除光标到行尾处的字符
  • Ctrl+Y : 撤销
  • Ctrl+C : 终止程序运行
  • Ctrl+Z : 将当前程序挂起,暂时不运行,暂停程序/命令
  • Ctrl+S :暂停屏幕的输出 (屏幕内容暂停,但不是不能继续执行命令)
  • Ctrl+q :恢复屏幕的输出

1.5. 常用命令

  • bg :将挂起的程序启动,在后台运行
  • fg :将挂起的程序或者后台运行的程序,放到前台运行
  • which ls : 查看命令ls的磁盘位置
  • history : 查看历史命令 (下面四个以!开头的命令都跟历史命令有关)
  • !number : 执行编号为number的历史命令
  • !string : 找到最近一个以string开头的历史命令执行
  • !$ : 可以把他理解为一个全局变量,永远指向上一个命令的最后一个参数
  • !! : 找到上一个命令并执行.比如,如果你在运行一个需要管理员权限的命令,但忘记在命令前加 sudo,那么就可以很方便地使用 sudo !! 来修复这个问题,而不用重新输入整条命令。

1.6 重定向

  • |:管道符号,将前一个命令的标准输出作为后一个命令的标准输入
  • 0 : 标准输入
  • 1 :标准输出
  • 2 :标准错误
  • > : 标准输出重定向 等价于1>
  • < : 标准输入重定向
  • >> :: 标准输出重定向,追加方式 等价于1>>
  • 2> :标准错误输出重定向
  • 2>> :标准错误输出重定向,追加方式
  • &> : 混合重定向,表示将标准输出,标准错误都重定向指定位置
  • 1>&2 : 将标准输出重定向到标准标错误
  • 2>&1 : 将标准错误重定向到到标准输出
# 2> 之间不能有空格,将标准错误追加到文件中
ls java 2> redirect2.txt

# 混合重定向
ls a &> a.txt 

#统计a.txt有多少行
wc -l < a.txt  # line
wc -c < a.txt  # char
wc -w < a.txt  # word

1.7 命令排序

  • 分号 分号分割的命令会依次执行,无论前面是否出现错误
  • && 前一个命令成功后才会执行下一个命令
  • || 前一个命令执行不成功才会执行下一条命令
date;date;

./configure && make && make install

ls /home/222/333 || mkdir -p /home/222/333

# 逻辑判断
ping -c1 www.baidu.com && echo "ping success" || echo "ping fail"

1.9 & 含义

  • command & : 命令最后加一个&,表示后台执行
  • command &> /dev/null : 混合重定向,/dev/null 是一个特殊的文件
  • command1 && command2 : 命令排序,逻辑判断

1.10 指令搜索顺序

  1. 如果以相对/绝对路径执行指令,则以此为准。如/bin/ls./ls
  2. 有alias找到该指令来执行
  3. 有bash内置的builtin指令来执行
  4. 通过$PATH这个变量的顺序搜索到的第一个指令来执行

可以通过type -a 命令 来查看命令顺序

1.11 通配符

  • * 匹配任意个字符(0到无穷)
  • ? 匹配任意一个字符
  • [abcd] 匹配括号内abcd中的任意一个字符
  • [0-9] 匹配0-9中任意一个字符
  • [^abcd] 取反

1.12 shell中的特殊字符

# : 注释符
\ : 将特殊字符或通配符还原为一般字符
; : 连续命令的界定
~ : 主文件夹
$ : 取用变量前置字符
& : 工作控制,将指令变成后台下工作
! : 否
/ : 路径分隔符
> : 输出重定向,覆盖
>>: 输出重定向,追加
' ' : 单引号,不具有变量置换的功能($ 变为纯文本)
" " : 具有变量置换的功能(会解析字符串)
(): 中间为子shell的起始与结束
{}: 中间为命令区块的组合

1.13 {}在 linux 中的作用

  • 花括号扩展: 在命令中,会先进行扩展解析,在执行命令。
echo file_{A,B,C}.txt
#file_A.txt file_B.txt file_C.txt

echo {A,B}_{1..3}
#A_1 A_2 A_3 B_1 B_2 B_3

cp file.{txt,bak}
# 等价于 cp file.txt file.bak
  • 在 Shell 脚本中组合命令
    • {} 之间的命令需要用分号;换行符分隔。
    • { 必须位于一行的开头,或后面紧随一个空格。
    • } 必须位于一行的开头,或前面紧随一个分号 ;。
    • } 之后不能有其他字符,包括注释。如果你需要添加注释,可以在 } 上面一行添加。
{
  echo "This is the start."
  echo "This is the middle."
  echo "This is the end."
}
{ echo "This is line 1"; echo "This is line 2"; } > combined_output.txt
  • 使用{}组合命令的意义

    • 代码组织:增加代码清晰度,知道这些代码要一起工作
    • 重定向 可以将一组命令的标准输出一起重定向到指定文件。例如,{ command1; command2; } > output.txt 将会把 command1command2 的输出都重定向到 output.txt
    • 变量作用域如果使用的是圆括号, 这里面定义的变量不会影响到主命令块。这有利于防止变量污染。
    • 并发执行:如果希望在后台并发执行一组命令,可以将它们放在一个命令块中,然后在后面添加 “&” 符号。例如 { command1; command2; } & 将会在后台执行这两个命令。
    • 条件执行:可以使用命令块与逻辑运算符一起工作,如 “&&” 和 “||”。例如,command1 && { command2; command3; } 如果 command1 执行成功,那么command2 和 command3将会执行。
  • {}在特定命令中作为参数的占位符

    • 如 find中,大括号 {} 被用作占位符,表示每一个找到的结果。
find . -name "*.txt" -exec rm {} \;

1.14 set -e

  • 在Bash 中使用set -e 选项。这个选项告诉 Bash 当任何命令执行失败时停止执行脚本。
set -e

{
  command1
  command2
} 

echo "Commands executed successfully"
  • 在这里 如果 command1 command2 有任何一个命令失败,都会立刻停止执行

1.15 ()在 linux 中的作用

  • 子shell命令组,跟前面大括号类似,不同的是使用圆括号是在子shell中执行。意味着在圆括号里面定义或更改的变量,不会影响到当前shell的变量值
    • 限制了变量作用阈
    • 子shell中运行,不影响当前shell环境
    • 虽然在子shell中执行,但是当前shell还是会等待子shell返回后才能继续执行
    • 可以充当匿名代码块
# 定义一个变量
var="Hello"

# 子 Shell 中修改变量的值,不影响外部 Shell 环境
(var="World"; echo "在子 Shell 中的变量值:$var")

# 外部 Shell 环境中的变量值没有改变
echo "外部 Shell 中的变量值:$var"

  • 命令替换:可以将一个命令的输出赋值给一个变量。
    • 命令替换需要在括号前面加$
    • `` 也能命令替换,如果出现嵌套情况下,可读性不是很好
    • 利用命令替换可以编写一些高效的脚本
# 使用反引号执行命令替换
result=`date`
echo "当前日期是:$result"

# 使用$()执行命令替换(推荐用法)
result=$(date)
echo "当前日期是:$result"

# 使用命令替换获取当前目录中的文件数量,并保存到变量 count 中
count=$(ls -1 | wc -l)

# 输出文件数量
echo "当前目录中的文件数量为:$count"

1.16 $n在 linux 中的作用

  • 在 可执行shell脚本中
    • $0: 脚本名称(包含路径,或相对或绝对)
    • $1: 脚本的第一个参数
    • $3: 脚本第3个参数
  • 在shell命令行中
    • $0: shell名称

1.17 !!:n在 linux 中的作用

  • !!: 上一条命令
  • !!:0: 上一条命令名称
  • !!:1:上一条命令第一个参数

1.18 什么是命令替换

命令替换是shell中的一种技术,能够将一个命令的输出作为另一个命令参数,或者赋值给一个变量。 有两种方式进行命令替换

  1. 使用$(command) ,推荐这种
  2. 使用`` 。这种不推荐,可读性不够好
cur_date=$(date)
ls $(pwd)
ls `pwd`
a = `expr 1 + 5`
echo "a + b = `expr $a + $b`"

1.19 exit命令

  • 退出命令,可以在后面跟一个退出状态码
  • 可以通过$?来检查退出状态码

2.0 在shell脚本中调用python

#!/usr/bin/bash
ls

python <<-EOF
print("hello world")
EOF
  • * :匹配任意多个字符
  • :匹配任意单个字符
  • [] : 匹配括号中的任意一个字符 [abc] [0-9] [^a-Z] ^表示取反
  • {} : 这个不算是匹配,这个效果如下

#  1.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt  9.txt 
touch {1..9}.txt

#   笛卡尔积a1.txt  a2.txt  a3.txt  b1.txt  b2.txt  b3.txt  c1.txt  c2.txt  c3.txt
touch {a..c}{1..3}.txt

# hello.  hello.img  hello.txt
touch hello.{,txt,img}

2.3 字符串拼接操作

  • 将两个字符串紧挨着写即完成拼接
  • 一般有空格就认为是两个字符串
echo "hello""world"

num1=1
num2=2
echo "$num1""$num2"    # 输出12

echo "hello"'world'
echo "today is "`date`

2.3 字符串截取

  • ${#变量名} :求字符串长度
  • ${变量名:start:length}
  • ${变量名:start} :注意分号之间不能有空格
  • ${变量名:0-start:length} : 从字符串右边开始第start开始,截取长度为length的子串
  • ${变量名:0-start}
  • ${变量名#str} : 截取str之后的字符串
  • ${变量名##str} :截取str之后的字符串 贪婪匹配
  • ${变量名%str} : 截取str之前的字符串
  • ${变量名%%str} : 截取str之前的字符串 贪婪匹配
  • ${变量名/旧子串/新子串} : 替换第一个匹配的子串
  • ${变量名//旧子串/新子串} : 替换全部旧子串
url=www.sina.com.cn

# 不是模糊匹配的时候,二者没区别,都表示若url以www开头,则输出www后面的内容
echo ${url#www}
echo ${url##www}

# 若是模糊匹配的时候,就有区别了
echo ${url#*.}
echo ${url##*.}

# 同上
echo ${url%.*}
echo ${url%%.*}

3. 变量

3.1 变量使用

  • 变量名=变量值 : 不允许使用空格
  • $变量名 :引用变量方法
  • unset 变量名 : 清除变量名
  • export 变量名=变量值 :添加为全局变量
num=100
echo $num
unset num
echo $num

3.2 系统变量

  • $0 当前脚本的名称
  • $n 当前脚本的第n个参数 n<=9
  • ${n} 当前脚本的第n个参数,n>9
  • $# 当前脚本的参数个数(不包括程序本身);
  • $* 当前脚本的所有参数(不包括程序本身);以字符串方式
  • $@ 当前脚本的所有参数(不包括程序本身);以数组方式
  • $? 脚本或程序执行完后的状态,返回0表示执行成功
  • $! 上一个后台进程的pid
  • $$ 程序本身的PID号。

4. 数组

4.1 定义数组

# 方式一, 空格分割元素
arr=(a1 a2 a3)

# 方式二: 这种类似于map
arr1=([0]=1 [3]="abc" [10]="abc")

# 直接赋值
arr[6]=100

4.2 获取数组

  • ${数组名[index]} : 获取指定索引元素
  • ${数组名[@]} : 获取数组中所有元素
  • ${数组名[*]} : 获取数组中所有元素
  • ${#数组名[@]} : 获取数组的长度或个数
  • ${#数组名[*]} : 获取数组的长度或个数
  • ${#数组名[index]} : 获取数组指定元素的长度
arr=(hello world 12 good work)

echo ${arr[0]}
echo ${arr[@]}
echo ${#arr[*]}
echo ${#arr[2]}

4.3 数组拼接

arr1=(hello world)
arr2=(good work)
arr3=(${arr1[*]} ${arr2[@]})

4.4 数组的删除

  • unset array_name[index] : 删除数组元素
  • unset array_name :删除整个数组

5. shell内置命令

5.1 命令的分类

  • shell内置命令
  • 文件系统中的可执行文件
  • type 命令 : 查看命令时shell内置命令还是可执行文件
  • 通常来说,内置命令会比外部命令执行的更快。
    • 外部命令需要触发磁盘IO,还需要fork出一个单独的进程执行,执行完后再退出
    • 内置命令相当于调用当前shell进程中的一个函数。减少上下文切换

5.2 常见的内置命令

  • alias :给命令创建别名
    • alias : 显示当前shell的所有别名列表
    • alias 别名='命令':定义别名
    • unalias 别名 : 删除别名
    • unalias -a :删除当前shell中的所有的别名
  • echo :输出字符串
    • echo 字符串 : 输出字符串,自动换行
    • echo -n 字符串 : 输出字符串,不会换行
    • echo -e "hello \n world":会解析转义字符
  • read [-options] [var1 var2 ...] : 读取控制台输入
    • read -p "请输入姓名:" name :prompt 交互式输入
    • read -n 10 name :读取10个字符,而不是整行字符
    • read -s name :静默模式,不会在屏幕上显示输入内容
    • read -t 10 name:设置超时时间为10s
read -p "请输入姓名,年龄,爱好: " name age hobby
read -n 1 -p '请输入一个字符: ' char
read -t 20 -sp '请输入密码(20秒内):' pwd1
  • exit : 退出

    • exit: 正确退出,默认返回状态码0
    • exit 非0数字 :代表命令执行失败,数字范围建议0~255
  • declare [+/-][aArxif][变量名=变量值] :设置变量

    • -:用来添加变量属性
    • +:用来取消变量的属性
    • a:array,设置普通索引数组
    • A:array,设置kay-value关联数组
    • r:readonly,将比变量设置为只读
    • x:export,设置变量为全局变量
    • i:int,设置变量为整型变量
    • f:function,设置为一个函数变量
# 查看所有的变量
declare
# 查看所有的函数的定义
declare -f
# 查看所有函数的名称列表
declare -F

# 关联数组,key可以是字符串
declare -A arr=([name]="李四" [age]=20 ["hobby"]="shell")

6. 运算符

6.1 整数算术运算符

只能计算整数

#!/bin/bash
a=1 b=2          # 声明变量a=1和b=2
echo "a=${a} b=${b}"
echo "a + b = `expr $a + $b`"
echo "a * b = `expr $a \* $b`"
echo "a - b = `expr $a - $b`"
echo "a * b = `expr $a \* $b`"   # * 要转移
echo "b / a = `expr $b / $a`"
echo "b % a = `expr $b % $a`"
echo "(b+a)*10"=`expr \( $b + $a \) \* 10`    # ( 要转义

6.2 整数比较运算符

方括号与括号里面的内容之间必须要有空格,因为方括号是内置命令,后面的是它的三处
只能比较整数

运算符说明举例
-eqequals 检测两个数是否相等,相等返回 0, 否则返回1。[ $a -eq $b ] 返回 1。
-nenot equals检测两个数是否不相等,不相等返回 true。[ $a -ne $b ] 返回 0。
-gtgreater than检测左边的数是否大于右边的,
是返回0, 否则1
[ $a -gt $b ] 返回 1。
-ltlower than检测左边的数是否小于右边的,
是返回0, 否则1
[ $a -lt $b ] 返回 0。
-gegreater equals检测左边的数是否大于等于右边的,
是返回0, 否则1
[ $a -ge $b ] 返回 1。
-lelower equals检测左边的数是否小于等于右边的,
是返回0, 否则1
[ $a -le $b ] 返回 0。
<检测左边的数是否小于右边的,
是返回0, 否则1
(($a<$b)) 返回0
<=检测左边的数是否小于等于右边的,
是返回0, 否则1
(($a<=$b)) 返回0
>检测左边的数是否大于右边的,
是返回0, 否则1
(($a>$b)) 返回1
>=检测左边的数是否大于等于右边的,
是返回0, 否则1
(($a>=$b)) 返回1
==检测左边的数是否等于右边的,
是返回0, 否则1
(($a==$b)) 返回1
!=检测左边的数是否不等于右边的,
是返回0, 否则1
(($a!=$b)) 返回0
#!/bin/bash
a=1 b=2
echo "a=${a} b=${b}"
if [ $a -eq $b ]
then
   echo "$a -eq $b : a 等于 b"
else
   echo "$a -eq $b: a 不等于 b"  # 输出这个
fi

if (($a <= $b))
then
   echo "$a <= $b: a 小于或等于 b"
else
   echo "$a <= $b: a 大于 b"
fi

6.3 字符串比较运算符

运算符说明举例
== 或 =相等。用于比较两个字符串或数字,相同则返回 0。可以使用=[ $a == $b ] 返回1
[ $a = $b ] 返回 1
[[ $a == $b ]] 返回1
[[ $a = $b ]] 返回1
!=不相等。用于比较两个字符串或数字,不相同则返回 0。[ $a != $b ] 返回 0
[[ $a != $b ]] 返回 0
<小于, 用于比较两个字符串或数字, 小于返回0, 否则返回1[ $a \< $b ] 返回 0
[[ $a < $b ]] 返回 0
>大于, 用于比较两个字符串或数字, 大于返回0, 否则返回1[ $a \> $b ] 返回 1
[[ $a > $b ]] 返回 1
-z检测字符串长度是否为0,如果长度为0返回则返回0, 否则返回1。[ -z $a ] 返回 false。
-n检测字符串长度是否不为 0,如果长度不为 0 则返回0, 否则返回1。[ -n “$a” ] 返回 true。
$检测字符串是否不为空,不为空返回0, 为空返回1。[ $a ] 返回 true。

字符串比较只能使用中括号这个内置命令

#!/bin/bash
a="hello"
b="wrold"

if [[ $c > $d ]]
then
   echo "$c > $d : c 大于 d"
else
   echo "$c > $d: c 不大于 d"
fi

if [ -z $a ]
then
   echo "-z $a : 字符串长度为 0"
else
   echo "-z $a : 字符串长度不为 0"
fi

# <=
`[[ "a" < "b" && "a" == "b" ]]`

总结

  • ()只能比较整数,不推荐
  • []可以比较整数和字符串,会将含有空格字符串进行分拆分割后比较,还有需要转义,也不推荐
  • [[]]可以比较整数和字符串,不用注意空格导致字符串分割问题,不需要转义
  • 所以最终结论就是,比较的时候推荐使用[[]]
a='a'
b='a b'
[ $a == $b ]    # bash: [: too many arguments
[[ $a == $b ]]

6.4 布尔运算符

运算符说明举例
!非运算,取反, 表达式为 true 则返回 false,
否则返回 true。
[ ! 表达式 ] 取反。
-oor 或运算,有一个表达式为 true 则返回 true。[ 表达式1 -o 表达式2 ]
-aand 与运算,两个表达式都为 true 才返回 true。[ 表达式1 -a 表达式2 ]

注意布尔运算符放在[] 或 与test命令配合使用才有效
主要用在test命令中

#!/bin/bash
a=1 b=2

if [ $a -lt 2 -a $b -gt 10 ]
then
   echo "$a 小于 2 且 $b 大于 10 : 返回 true"   
else
   echo "$a 小于 2 且 $b 大于 10 : 返回 false"  # $b -gt 10不成立, 输出这个表达式
fi

if [ ! $a -gt $b ]
then
   echo "$a 大于 $b 取反 : 返回 true"
else
   echo "$a 大于 $b 取反 : 返回 false"   # $a -gt $b 为true , 取反为false, 输出这个表达式
fi

6.5 逻辑运算符

运算符说明举例
&&逻辑的 AND[[ 表达式1 && 表达式2 ]]
``
!逻辑非[[ ! 表达式 ]]
#!/bin/bash

a=1 b=2

if [[ $a -lt 10 && $b -gt 10 ]]
then
   echo "返回 true" 
else
   echo "返回 false"  # $b -gt 10 不成立, 输出false
fi

if [[ $a -lt 10 || $b -gt 10 ]]
then
   echo "返回 true"   # $a -lt 10 成立,  输出true
else
   echo "返回 false"  
fi

6.6 文件测试运算符

操作符说明举例
-b file检测文件是否是块设备文件,如果是,则返回 true。[ -b $file ] 返回 false。
-c file检测文件是否是字符设备文件,如果是,则返回 true。[ -c $file ] 返回 false。
-d filedirectory, 检测文件是否是目录,如果是,则返回 true。[ -d $file ] 返回 false。
-f filefile, 检测文件是否是普通文件(既不是目录,也不是设备文件)
,如果是,则返回 true。
[ -f $file ] 返回 true。
-g file检测文件是否设置了 SGID 位,如果是,则返回 true。[ -g $file ] 返回 false。
-k file检测文件是否设置了粘着位(Sticky Bit),如果是,
则返回 true。
[ -k $file ] 返回 false。
-p file检测文件是否是有名管道文件,如果是,则返回 true。[ -p $file ] 返回 false。
-u file检测文件是否设置了 SUID 位,如果是,则返回 true。[ -u $file ] 返回 false。
-r fileread,检测文件是否可读,如果是,则返回 true。[ -r $file ] 返回 true。
-w filewrite,检测文件是否可写,如果是,则返回 true。[ -w $file ] 返回 true。
-x fileexecute, 检测文件是否可执行,如果是,则返回 true。[ -x $file ] 返回 true。
-s filesize, 检测文件是否为空(文件大小是否大于0)
,不为空返回 true。
[ -s $file ] 返回 true。
-e fileexists, 检测文件(包括目录)是否存在,如果是,
则返回 true。
[ -e $file ] 返回 true。
file1 -nt file2new than(nt), file1是否比file2新[ file1 -nt file2 ]
file1 -ot file2old than(ot), file1是否比file2旧[ file1 -ot file2 ]
#!/bin/bash

file="/root/operation1.sh"
file2="/root/operation2.sh"
if [ file -nt file2 ]   # 可以用[[ ]]
then
   echo "operation1.sh文件比operation2.sh文件新"
else
   echo "operation1.sh文件不比operation2.sh文件新"
fi

7. shell计算命令

7.1 expr命令

  • expr 算术运算符表达式 返回运算结果
  • expr length 字符串 返回字符串长度
  • expr substr 字符串 start end 截取字符串字串
  • expr index 被查找字符串 需要查找的字符 :索引字串首次出现位置
  • expr match 字符串 正则表达式 返回匹配的长度
  • expr 字符串 : 正则表达式 也是正则匹配,返回匹配的长度
result=`expr \( 10 + 10 \) \* 2 + 100`

echo "正则表达式匹配查找hello world字符串中w前面任意字符的总长度=`expr "hello world" : ".*w"`"

特点

  • 所有类型的shell终端都支持
  • 需要对一些符号进行转义
  • 不是很推荐使用

7.2 (()) 命令 推荐

(( )) , 用于进行数学运算表达式的执行
可以使用$获取 (( )) 表达式命令的结果

运算操作符/运算命令说明
((a=1+6))
((b=a-1))
((c=a+b))
这种写法可以在计算完成后给变量赋值。以 ((b=a-1)) 为例,
即将 a-1 的运算结果赋值给变量 c。 注意,使用变量时不用加$前缀,
(( )) 会自动解析变量名。
a=$((1+6)
b=$((a-1))
c=$((a+b))
可以在 (( )) 前面加上$符号获取 (( )) 命令的执行结果,
也即获取整个表达式的值。以 c=$((a+b)) 为例,即将 a+b 这个
表达式的运算结果赋值给变量 c。 注意,如果 c=((a+b)) 这样的写
法是错误的,不加$就不能取得表达式的结果。
((a>7 && b==c))(( )) 也可以进行逻辑运算,在 if 语句中常会使用逻辑运算。
echo $((a+10))需要立即输出表达式的运算结果时,可以在 (( )) 前面加$符号。
((a=3+5, b=a+10))对多个表达式同时进行计算, 多表表达式使用","号隔开

双括号中符号之间有无空格都可以 (( a = 1 + 6 )) 等价于 ((a=1+6))

7.3 let命令

这个命令没有输出
let 赋值表达式
let 变量名1=整数运算表达式1 变量名2=整数运算表达式2 ...

a=1
b=2
let c=a+b
echo $c
let "result = (a<b)"
echo $result    # 1, 1为真值
  • 支持标准运算符和逻辑运算符。±*/% && ||
  • 支持变量自增自减
  • 如果算术表达式中不包含空格或特殊字符,可以直接不使用双引号。,否则需要双引号括起来

7.4 $[]命令

  • 只能进行整数运算
  • 能够对单个表达式的计算求值与输出
  • 特殊字符不需要转义
  • 功能单一,也不是很推荐

7.5 小结

expr

​ 优点: 可以直接输出

​ 缺点: 计算表达式里面引用变量使用$, 特殊字符需要转义 只能计算一个表达式

(()) (推荐方式)

​ 优点: 直接输出, 里面直接使用变量名, 特殊字符不需要转义, 多个表达式赋值

​ 缺点: 需要获取值以后才可以输出

let 次推荐

​ 优点: 赋值简单,特殊字符不需要转义,

​ 缺点: 不能直接输出

$[]

​ 优点: ,特殊字符不需要转义,

​ 缺点: 不能多表达是计算,

7.6 bc命令

  • bc命令是linux的简单计算器

task.txt文件内容

108*67+12345
58+2007*11
# -q  quiet,不显示欢迎信息
bc -q task.txt
# 输出 19581 和 22135
# -l 表示使用mathlib, 使用标准数学库
bc -q -l 
e(5)
quit

echo "expression" | bc [options] 利用管道作为表达式的输入

echo "9*9" | bc
b=$(bc << EOF
1+1
2+2
3+3
EOF
)
echo $b
# 2 4 6

8 流程控制语句

8.1 if else语句

if  条件1
then
   命令1
elif 条件2
then
    命令2
else
   命令N
fi

8.2 test命令

8.2.1 整数比较

if test 数字1 options 数字2 
then  
...
fi

options具体如下

参数说明
-eq等于则为真
-ne不等于则为真
-gt大于则为真
-ge大于等于则为真
-lt小于则为真
-le小于等于则为真
#!/bin/bash
num1=1 num2=1 num3=2
if test $num1 -eq $num2
...

8.2.2 字符串比较

参数说明
= 或 ==等于, 等于返回0代表成功,否则返回1代表失败
!=不等于
\<小于
\>大于
-z 字符串字符串的长度为零则为真
-n 字符串字符串的长度不为零则为真
if test $str1 \> $str2
if test -z $str2

8.2.3 文件测试

参数说明
-e 文件名exists, 如果文件存在则为真
-r 文件名read,如果文件存在且可读则为真
-w 文件名write,如果文件存在且可写则为真
-x 文件名execute,如果文件存在且可执行则为真
-s 文件名string,如果文件存在且至少有一个字符则为真
-d 文件名directory,如果文件存在且为目录则为真
-f 文件名file,如果文件存在且为普通文件则为真
-c 文件名character,如果文件存在且为字符型特殊文件则为真
-b 文件名如果文件存在且为块特殊文件则为真

Shell提供了与( -a )、或( -o )、非( ! )三个逻辑操作符用于将测试条件连接起来,其优先级为:“!“最高,”-a"次之,”-o"最低, 语法

test 条件1 -o 条件2 -a 条件3 ...
```shell
#!/bin/bash
if test -e ./control1.sh -a -e ./control2.sh
then
    echo '两个文件都存在!'
else
    echo '可能有一个或两个文件不存在'
fi

8.3 case 语句

  • 支持部分正则的匹配功能
格式说明
*表示任意字符串。
[abc]表示 a、b、c 三个字符中的任意一个。比如,[15ZH] 表示 1、5、Z、H 四个字符中的任意一个。
[m-n]表示从 m 到 n 的任意一个字符。比如,[0-9] 表示任意一个数字,[0-9a-zA-Z] 表示字母或数字。
|表示多重选择,类似逻辑运算中的或运算。比如,abc | xyz 表示匹配字符串 “abc” 或者 “xyz”。
casein
匹配模式1)
    命令1
    命令2
    ...
    ;;
匹配模式2)
    命令1
    命令2
    ...
    ;;
*)
    命令1
    命令2
    ...
    ;;
esac
#!/bin/bash
read -p "请输入一个0~7的数字:" number
case $number in
1)
    echo "星期一"
	;;
2)
    echo "星期二"
    ;;
3)
    echo "星期三"
    ;;
4)
    echo "星期四"
    ;;
5)
    echo "星期五"
    ;;
6)
    echo "星期六"
    ;;
0|7)
    echo "星期日"
    ;;
*)
    echo "您输入的数字无效"
    ;; 
esac

8.4 while循环

while 条件
do
	命令1
	命令2
	...
	continue; # 结束当前这一次循环, 进入下一次循环
	break; # 结束当前循环
done
#!/bin/bash
read -p "请输入一个数字:" number
i=0
while [[ $i < $number ]]
do
  echo "hello world"
  ((i++))
done

无限循环

while :
do
    command
done

# 或者
while true
do
    command
done

8.5 until语句

until 条件
do
    命令
done
#!/bin/bash
read -p "请输入一个数字:" number
i=0
until [[ ! $i < $number ]]
do
  echo "hello world"
  ((i++))
done

8.6 for语句

for var in item1 item2 ... itemN
do
    命令1
    命令2
    ...
done

# 或
```shell
for var in {start..end}
do
	命令
done

# 或
for((i=start;i<=end;i++))
do
	命令
done
#!/bin/bash
for i in 1 2 3 4 5
do
 echo "hello world"
done

8.7 select 语句

select 会根据用户的输入信息走下面的逻辑

select var in menu1 menu2 ...
do
    命令
done
#!/bin/bash
echo "你的爱好是什么?"
select hobby in "编程" "游戏" "篮球" "游泳"
do
	echo $hobby
    break
done
echo "你的爱好是:${hobby}"

注意: select 是无限循环(死循环),输入空值,或者输入的值无效,都不会结束循环,只有遇到 break 语句,或者按下 Ctrl+D 组合键才能结束循环。

执行命令过程中: 终端会输出 #? 代表可以输入选择的菜单编号

9 shell 函数

9.1 basename

basename [string / pathname] [suffix]  

根据根据指定字符串或路径名进行截取文件名, 比如: 根据路径"/one/two/aa.txt", 可以截取出aa.txt

suffix: 用于截取的时候去掉指定的后缀名.

basename /home/ljs/a.txt
basename /home/ljs/a.txt .txt

9.2 dirname

dirname 文件绝对路径

从指定的文件绝对路径, 去除文件名,返回剩下的前缀目录路径

9.3 自定义函数

# 函数的定义
[ function ] funname ()
{
    命令
    [return 返回值]

}

# 调用函数
funname 传递参数1 传递参数2 ...
#!/bin/bash
demo()
{
    echo "执行了函数"
}

# 调用函数
demo
#!/bin/bash
sum()
{
    echo "求两个数的和..."
    read -p "输入第一个数字: " n1
    read -p "输入第二个数字: " n2
    echo "两个数字分别为 $n1$n2 "
    return $(($n1+$n2))
}

# 调用函数
sum
echo "两个数字的和为: $? "  # 获取函数返回值

有参函数

#!/bin/bash
funParam(){
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "第十个参数为 $10 !"
    echo "第十个参数为 ${10} !"
    echo "第十一个参数为 ${11} !"
    echo "参数总数有 $# 个!"
    echo "作为一个字符串输出所有参数 $* !"
}
# 调用函数
funParam 1 2 3 4 5 6 7 8 9 10 22

10 .补充

10.1 ()单小括号的作用

  • 命令组:括号中的命令会由子shell执行,可以有多个命令,同一行的命令要用分号分割
  • 命令替换 :如a=$() , 将命令的输出赋值给a
  • 命令初始化

10.2 (()) 双小括号的作用

  • 表达式计算 可以在里面重新为变量赋值 如 ((num=5))
  • 表达式结果替换 如 a=$((1+3)) 将4赋值给a
  • 括号中的运算符,表达式符合c语言运算规则的都可以用在((expr))中,甚至三元运算

10.3 [] 单方括号的作用

  • [是bash内置命令 : 等同于test,用来做条件判断
  • 数组中表示取指定下标的元素

10.4 [[]]双方括号的作用

  • [[ 是bash的一个内置关键字 :效果等同于单方括号,但是通用性更好
    • 支持 && || > < 如[[ $a!=1 && $a!=2 ]] 要用单括号则为 [ $a != 1 ] && [ $a != 2 ] 或 [ $a -ne 1 -a $a != 2 ]
    • 字符串比较的时候 左边可以看成正则模式如 [[ hello ==hell? ]]
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值