续shell脚本学习Day1

检查系统环境变量的命令

1
set

输出所有变量(全局、局部)

1
env

只显示全局变量

1
declare

输出所有变量,如同set

1
export

显示和设置环境变量的值

撤销环境变量

1
unset <变量名>

设置只读变量

1
readonly <变量名>=<变量值>

只读变量只能赋一次值;

当shell结束时,只读变量失效。

系统保留环境变量关键字

1
export |awk -F '[ :=]' '{print $3}'

利用awk对export取出的环境变量结果进行格式化

bash多命令执行

使用分号;分隔

1
ls /data/;cd /tmp/

shell变量之特殊变量

shell的特殊变量,用在如脚本,函数传递参数使用

  • 获取shell脚本文件名,以及脚本路径
1
$0 
  • 获取shell脚本的第n个参数,$1,$2,$9,大于9则写${10},参数空格隔开
1
2
3
4
$1
$2
$9
${10}
  • 获取执行的shell脚本后的参数总个数
1
$#
  • 获取shell脚本所有参数,不加引号等同于$@作用,加上引号时,接收所有参数为单个字符串
1
$*
  • 获取shell脚本所有参数,不加引号等同于$#,加上引号时,接收所有参数为独立字符串
1
$@

特殊状态变量

  • 上一次命令执行状态返回值,0正常,非0失败
1
$?

实例

脚本控制返回值

首先编写sv1.sh脚本

1
2
3
4
5
6
7
#! /bin/bash
[ $# -ne 2 ]&&{
echo "must be two args"
echo ‘$? return 119’
exit 119 #终止程序运行且返回119状态码,提供给当前shell的$?变量,若在函数中可以使用return 119
}
echo '$? return 0'

解释

1
2
3
$# 执行的shell脚本后的参数总数
-ne 不等于的情况
&& 与

运行

1
2
3
4
5
6
7
8
9
10
[root@192 ~]# bash sv1.sh x y
$? return 0
[root@192 ~]# echo $?
0

[root@192 ~]# bash sv1.sh x y z
must be two args
0 return 119
[root@192 ~]# echo $?
119
  • 当前shell脚本的进程号
1
$$

实例一

编写sv2.sh脚本

1
2
#! /bin/bash
echo "$$"
1
2
[root@192 ~]# bash sv2.sh
1725
  • 上一次后台进程的PID
1
$!

实例

拓展

怎么让程序后台执行

1
nohup <*.sh/程序> & 1> /dev/null
1
2
3
4
5
6
7
8
9
[root@192 ~]# nohup ping baidu.com & 1> /dev/null
[1] 1729
[root@192 ~]# nohup: 忽略输入并把输出追加到"nohup.out"

[root@192 ~]# ps -ef|grep ping
root 1729 1670 0 20:42 pts/0 00:00:00 ping baidu.com
root 1731 1670 0 20:43 pts/0 00:00:00 grep --color=auto ping
[root@192 ~]# echo $!
1729
  • 上一次执行命令的最后一个参数
1
$_

实例

1
2
3
4
[root@192 ~]# bash sv1.sh x y
$? return 0
[root@192 ~]# echo $_
y

shell子串

bash一些的基础内置命令

1
2
3
4
5
6
echo
eval
exec
export
read
shift

echo命令

参数

1
2
3
4
5
6
7
-n 不换行输出
-e 解析字符串中的特殊符号

\n 换行
\r 回车
\t 指标符(四个空格)
\b 退格

eval命令

执行多个命令

1
2
3
4
5
6
7
8
[root@192 ~]# ls;cd /tmp/
anaconda-ks.cfg hello.sh nohup.out sv2.sh
blog node-v16.16.0-linux-x64 sv1.sh x.sh
[root@192 tmp]# cd /root

[root@192 ~]# eval ls;cd /tmp/
anaconda-ks.cfg hello.sh nohup.out sv2.sh
blog node-v16.16.0-linux-x64 sv1.sh x.sh

省略eval直接用分号;效果相同

exec命令

不创建子进程,执行后续命令,且执行完毕后,自动exit

1
2
[root@192 ~]# exec date
20220714日 星期四 21:06:09 CST

shell子串的花式用法

语法

1
2
3
4
5
6
7
8
9
10
${<变量>}					返回变量值
${#<变量>} 返回变量长度,字符长度
${<变量:<start>} 返回变量start数值之后的字符
${<变量:<start>:<length>} 返回变量start数值之后的字符,字符长度为length
${<变量>#word} 从变量开头删除最短匹配的word子串
${<变量>##word} 从变量开头删除最长匹配的word子串
${<变量>%word} 从变量结尾删除最短的word子串
${<变量>%%word} 从变量结尾删除最长的word子串
${<变量>/pattern/string} 用string代替第一个匹配到的pattern
${<变量>//pattern/string} 用string代替所有匹配到的pattern

实例

1
name=123abc

返回变量值

1
2
[root@192 ~]# echo ${name}
123abc

返回变量长度,字符长度

1
2
[root@192 ~]# echo ${#name}
6

返回变量start数值之后的字符

1
2
[root@192 ~]# echo ${name:3}
abc

返回变量start数值之后的字符,字符长度为length

1
2
3
4
[root@192 ~]# echo ${name:2:1}
3a
[root@192 ~]# echo ${name:3:2}
ab

从变量开头删除最短匹配的word子串

1
2
3
[root@192 ~]# name=111bbb333
[root@192 ~]# echo ${name#1*b}
bb333

从变量开头删除最长匹配的word子串

1
2
3
[root@192 ~]# name=111bbb333
[root@192 ~]# echo ${name##1*b}
333

从变量结尾删除最短的word子串

1
2
3
[root@192 ~]# name=111bbb333
[root@192 ~]# echo ${name%b*3}
111bb

从变量结尾删除最长的word子串

1
2
3
[root@192 ~]# name=111bbb333
[root@192 ~]# echo ${name%%b*3}
111

用string代替第一个匹配到的pattern

1
2
3
[root@192 ~]# name=111bbb333
[root@192 ~]# echo ${name/bbb/BBB}
111BBB333

用string代替所有的匹配到的pattern

1
2
3
[root@192 ~]# name=111bbb333bbb
[root@192 ~]# echo ${name//bbb/BBB}
111BBB333BBB

计算变量长度的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@192 ~]# name=012345
#法1 速度最快
[root@192 ~]# echo ${#name}
6
#法2
[root@192 ~]# echo ${name}|wc -L
6
#法3
[root@192 ~]# expr length "${name}"
6
#法4
[root@192 ~]# echo "${name}" | awk '{print length($0)}'
6

参数大写L计算值的字符个数,小写l计算值的行数

补充

wc命令参数用法

1
2
3
4
5
6
7
8
9
[root@192 ~]# cat book.txt
01
012
012
01234
[root@192 ~]# cat book.txt|wc -l
4
[root@192 ~]# cat book.txt|wc -L
5

字符串长度统计方法速度比较

统计命令执行时长

1
time <命令>

首先介绍一下for循环的语法

1
2
3
4
for <变量> in {1..100}
do
<命令>
done

{1..100}表示1到100的序列

通过时长统计命令对前文计算长度的4种方法速度进行对比

法1 使用${<变量>}计算时间

1
for num in {1..3};do echo $num;done
1
2
3
4
5
6

[root@192 ~]# time for n in {1..10000};do char=`seq -s "test" 100`;echo $ ${#char} &>/dev/null;done

real 0m12.893s
user 0m4.537s
sys 0m9.267s

法2 使用wc -L命令计算时间

1
2
3
4
5
[root@192 ~]# time for n in {1..10000};do char=`seq -s "test" 100`;echo $ ${char} |wc -L &>/dev/null;done

real 0m27.701s
user 0m10.556s
sys 0m28.359s

法3 使用expr的length命令计算

1
2
3
4
5
[root@192 ~]# time for n in {1..10000};do char=`seq -s "test" 100`;expr length "${char}" &>/dev/null;done

real 0m26.460s
user 0m7.414s
sys 0m21.406s

法4 使用awk的计算

1
2
3
4
5
[root@192 ~]# time for n in {1..10000};do char=`seq -s "test" 100`;echo $ ${char} |awk '{print length($0)}' &>/dev/null;done

real 0m31.735s
user 0m9.795s
sys 0m34.187s

shell编程,尽量使用Linux内置的命令,内置的操作和内置的函数,效率最高C语言开发效率最高,尽可能的减少管道符操作