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终端启动时脚本文件执行顺序
/etc/profile
- 系统级登录状态全局配置。
- 开机时或切换用户登录时执行一次,且只执行一次。
针对所有类型的 shell 终端有效
- 里面默认会调用
/etc/profile.d/*.sh
脚本。
$HOME/.bash_profile
- 用户级登录状态私有配置,可以覆盖全局配置。
- 也是用户登录时执行一次,且只执行一次
只针对 bash 类型的 shell 终端有效
bash类型终端,如果发现有这个配置文件,会执行这个文件,然后默认会忽略.profile文件。
$HOME/.profile
- 用户级登录状态私有配置,可以覆盖全局配置
- 也是用户登录时执行一次
针对所有类型的 shell 终端有效
$HOME/.bashrc
- 用户私有配置。
- 针对 bash 终端有效,打开新的 bash 会执行一次
-针对 Bash shell 的非登录、交互式 shell
/etc/bashrc
- 全局配置
- 针对bash终端有效,非登录时打开终端会执行一次
- 在ubantu中是
/etc/bash.bashrc
$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 类型的终端,他们都是用户级别的私有配置
~/.bash_profile
~/.bash_login
~/.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 指令搜索顺序
- 如果以相对/绝对路径执行指令,则以此为准。如
/bin/ls
或./ls
- 有alias找到该指令来执行
- 有bash内置的builtin指令来执行
- 通过$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
将会把command1
和command2
的输出都重定向到output.txt
。变量作用域
:如果使用的是圆括号
, 这里面定义的变量不会影响到主命令块。这有利于防止变量污染。并发执行
:如果希望在后台并发执行一组命令,可以将它们放在一个命令块中,然后在后面添加 “&” 符号。例如{ command1; command2; } &
将会在后台执行这两个命令。条件执行
:可以使用命令块与逻辑运算符一起工作,如 “&&” 和 “||”。例如,command1 && { command2; command3; }
如果command1
执行成功,那么command2 和 command3
将会执行。
-
{}在特定命令中作为参数的占位符
- 如 find中,大括号
{}
被用作占位符,表示每一个找到的结果。
- 如 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中的一种技术,能够将一个命令的
输出
作为另一个命令
的参数
,或者赋值
给一个变量
。 有两种方式进行命令替换
- 使用
$(command)
,推荐这种- 使用
``
。这种不推荐,可读性不够好
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
: 正确退出,默认返回状态码0exit 非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 整数比较运算符
方括号与括号里面的内容之间必须要有空格,因为方括号是内置命令,后面的是它的三处
只能比较整数
运算符 | 说明 | 举例 |
---|---|---|
-eq | equals 检测两个数是否相等,相等返回 0, 否则返回1。 | [ $a -eq $b ] 返回 1。 |
-ne | not equals检测两个数是否不相等,不相等返回 true。 | [ $a -ne $b ] 返回 0。 |
-gt | greater than检测左边的数是否大于右边的, 是返回0, 否则1 | [ $a -gt $b ] 返回 1。 |
-lt | lower than检测左边的数是否小于右边的, 是返回0, 否则1 | [ $a -lt $b ] 返回 0。 |
-ge | greater equals检测左边的数是否大于等于右边的, 是返回0, 否则1 | [ $a -ge $b ] 返回 1。 |
-le | lower 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。 | [ ! 表达式 ] 取反。 |
-o | or 或运算,有一个表达式为 true 则返回 true。 | [ 表达式1 -o 表达式2 ] |
-a | and 与运算,两个表达式都为 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 file | directory, 检测文件是否是目录,如果是,则返回 true。 | [ -d $file ] 返回 false。 |
-f file | file, 检测文件是否是普通文件(既不是目录,也不是设备文件) ,如果是,则返回 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 file | read,检测文件是否可读,如果是,则返回 true。 | [ -r $file ] 返回 true。 |
-w file | write,检测文件是否可写,如果是,则返回 true。 | [ -w $file ] 返回 true。 |
-x file | execute, 检测文件是否可执行,如果是,则返回 true。 | [ -x $file ] 返回 true。 |
-s file | size, 检测文件是否为空(文件大小是否大于0) ,不为空返回 true。 | [ -s $file ] 返回 true。 |
-e file | exists, 检测文件(包括目录)是否存在,如果是, 则返回 true。 | [ -e $file ] 返回 true。 |
file1 -nt file2 | new than(nt), file1是否比file2新 | [ file1 -nt file2 ] |
file1 -ot file2 | old 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”。 |
case 值 in
匹配模式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? ]]