shell

shell

https://github.com/dylanaraps/pure-bash-bible?tdsourcetag=s_pcqq_aiomsg


什么是shell

shell是一个命令解释器,它在操作系统的最外层,负责直接与用户对话,把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出到屏幕返回给用户,这种对话方式可以是交互式(从键盘输入命令,可以立即得到shell的回应),或非交互(执行脚本程序)的方式

shell种类

交互式shell
非交互式shell
登录式shell

/etc/profile -> /etc/profile.d/*.sh -> ~/.bash_profile -> ~/.bashrc -> /etc/bashrc

非登录式shell

~/.bashrc -> /etc/bashrc

shell执行方式

解释器执行 (生成一个子shell执行)
添加执行权限(默认根据脚本第一行指定的解释器处理,如果没写以当前默认Shell解释器执行)
source 命令执行(以当前默认Shell解释器执行)

子shell

在父shell中执行一个shell脚本
在父shell中执行一条命令,在命令的末尾加上&
在父shell中执行一条命令,使用 ( ) 中执行
在父shell中执行带管道的命令


切换shell

chsh -s /bin/bash

shell应用场景

  • 系统基础配置
  • 部署应用服务
  • 配置应用服务
  • 部署业务代码
  • 应用服务备份
  • 日志分析
  • 监控应用服务

shell基础

  • 命令补全和文件路径补全, 如果写错无法补全 table
  • 命令历史记忆功能 history
  • 别名功能 alias、unalias
  • 常用快捷键 ctrl+u,k,a,e,l,c,z,d,r
  • 前后台作业控制 bg,fg,jobs,screen
  • 输入输出重定向 > >> 2> 2>> < << &> cat
  • | 将前者命令的标准输出交给后者命令的输入
  • |& 将前者命令的错误输出交给后者命令的输入
  • 命令之间的关系
    ; 没有逻辑关系,无论分号前面的命令执行是否成功都执行后者命令
    && 前面执行成功, 则执行后者
    || 前面执行不成功, 则执行后者

shell通配符

* 匹配任意多个字符
? 匹配任意一个字符
[] 匹配括号中任意一个字符a-z,0-9,A-Z,a-Z
() 在子 shell 中执行(cd /boot;ls) (umask 077; touch file1000)
{} 集合 touch file{1…9}
\ 转义符

shell模式匹配

使用shopt 内置命令启用shell选项 (extglob) 则会识别几个扩展模式匹配运算符。
模式列表是由 | 分割

查看shell选项 extglob

shopt |grep extglob

启动shell选项 extglob

shopt -s extglob

关闭shell选项 extglob

shopt -u extglob
模式说明
?(pattern-list)匹配给定模式零或一次
*(pattern-list)匹配给定模式零次或多次
+(pattern-list)匹配给定模式一次或多次
@(pattern-list)匹配给定模式之一
!(pattern-list)匹配除了给定的模式
[root@mycentos6-clone ~]# ll
total 0
-rw-r--r-- 1 root root 0 Nov  1 07:02 123
-rw-r--r-- 1 root root 0 Nov  1 07:02 aaaac
-rw-r--r-- 1 root root 0 Nov  1 06:51 aaab
-rw-r--r-- 1 root root 0 Nov  1 07:02 aad
-rw-r--r-- 1 root root 0 Nov  1 07:02 aadg
-rw-r--r-- 1 root root 0 Nov  1 07:02 bb
-rw-r--r-- 1 root root 0 Nov  1 07:02 c
 [root@mycentos6-clone ~]# ls !(c|bb|123)
aaaac  aaab  aad  aadg
[root@mycentos6-clone ~]# rm !(c|bb|123) -f
[root@mycentos6-clone ~]# ll
total 0
-rw-r--r-- 1 root root 0 Nov  1 07:02 123
-rw-r--r-- 1 root root 0 Nov  1 07:02 bb
-rw-r--r-- 1 root root 0 Nov  1 07:02 c

单引号-双引号-没有引号

引号和不加引号的区别1

[root@oldboytx ~]# touch a b
[root@oldboytx ~]# ll
total 0
-rw-r--r--. 1 root root 0 Jun 25 16:25 a
-rw-r--r--. 1 root root 0 Jun 25 16:25 b
[root@oldboytx ~]# touch "a b"
[root@oldboytx ~]# ll
total 0
-rw-r--r--. 1 root root 0 Jun 25 16:25 a
-rw-r--r--. 1 root root 0 Jun 25 16:25 a b
-rw-r--r--. 1 root root 0 Jun 25 16:25 b

引号和不加引号的区别2:

[root@oldboy36 tmp]# ll
总用量 0
-rw-r--r-- 1 root root 0 6月  25 19:36 ?
-rw-r--r-- 1 root root 0 6月  25 19:32 *
-rw-r--r-- 1 root root 0 6月  25 19:33 aa
-rw-r--r-- 1 root root 0 6月  25 19:33 abc
-rw-r--r-- 1 root root 0 6月  25 19:33 b
[root@oldboy36 tmp]# ll ?
-rw-r--r-- 1 root root 0 6月  25 19:36 ?
-rw-r--r-- 1 root root 0 6月  25 19:32 *
-rw-r--r-- 1 root root 0 6月  25 19:33 b
[root@oldboy36 tmp]# ll "?"
-rw-r--r-- 1 root root 0 6月  25 19:36 ?
[root@oldboy36 tmp]# ll *
-rw-r--r-- 1 root root 0 6月  25 19:36 ?
-rw-r--r-- 1 root root 0 6月  25 19:32 *
-rw-r--r-- 1 root root 0 6月  25 19:33 aa
-rw-r--r-- 1 root root 0 6月  25 19:33 abc
-rw-r--r-- 1 root root 0 6月  25 19:33 b
[root@oldboy36 tmp]# ll "*"
-rw-r--r-- 1 root root 0 6月  25 19:32 *

双引号和单引号区别1:

关于$

[root@oldboytx ~]# echo "$LANG"
en_US.UTF-8
[root@oldboytx ~]# echo '$LANG'
$LANG

双引号和单引号区别2:

关于``

[root@oldboytx ~]# echo "`which awk`"
/bin/awk
[root@oldboytx ~]# echo '`which awk`'
`which awk`

双引号和单引号区别3:

关于!

[root@oldboytx ~]# echo '!ll'
!ll
[root@oldboytx ~]# echo "!ll"
echo "ll /bin/awk "
ll /bin/awk 

shell搜索命令的顺序

别名(alias)—> 函数(function)—> Bash内置命令 —> $PATH环境变量


shell常用命令与工具

cat

cat<<-EOF
    1.[install lamp]
    2.[install lnmp]
    3.[exit]
EOF
cat >> /etc/profile <<'EOF'
$PATH
EOF

eval

  • 执行参数做为shell命令

tee

  • 从标准输入读取写到标准输出和文件
  • -a 追加到文件

printf

a=1
b=2
printf "a=%d,b=%d\n" $a $b

:

空命令
可以做多行注释,可以为变量设置默认值

echo

http://man7.org/linux/man-pages/man4/console_codes.4.html

字体颜色

echo -e "\033[30m 黑色字oldboy trainning \033[0m"
echo -e "\033[31m 红色字oldboy trainning \033[0m"
echo -e "\033[32m 绿色字oldboy trainning \033[0m"
echo -e "\033[33m 黄色字oldboy trainning \033[0m"
echo -e "\033[34m 蓝色字oldboy trainning \033[0m"
echo -e "\033[35m 紫色字oldboy trainning \033[0m"
echo -e "\033[36m 天蓝字oldboy trainning \033[0m"
echo -e "\033[37m 白色字oldboy trainning \033[0m"

背景颜色

echo -e "\033[40;37m 黑底白字 welcome to old1boy\033[0m"
echo -e "\033[41;37m 红底白字 welcome to old2boy\033[0m"
echo -e "\033[42;37m 绿底白字 welcome to old3boy\033[0m"
echo -e "\033[43;37m 黄底白字 welcome to old4boy\033[0m"
echo -e "\033[44;37m 蓝底白字 welcome to old5boy\033[0m"
echo -e "\033[45;37m 紫底白字 welcome to old6boy\033[0m"
echo -e "\033[46;37m 天蓝白字 welcome to old7boy\033[0m"
echo -e "\033[47;30m 白底黑字 welcome to old8boy\033[0m"

trap

trap [-lp] [[arg] signal_spec …]
-l # 打印编号1-64编号信号名称
arg # 捕获信号后执行的命令或者函数
signal_spec # 信号名或编号

trap “” 2 # 不指定arg就不做任何操作,后面也可以写多个信号,以空格分隔

trap ':' INT EXIT TSTP TERM HUP

mkpasswd openssl

mkpasswd -l 10 -c 3 -C 3 -d 3
openssl rand -base64 80

basename dirname

basename /etc/init.d/network 
network

dirname /etc/init.d/network 
/etc/init.d


shell脚本

脚本第一行

指定脚本解释器

#!/bin/sh
#!/bin/bash
#! /usr/bin/awk
#! /bin/sed
#! /usr/bin/tclsh
#! /usr/bin/expect
#! /usr/bin/perl
#! /usr/bin/env python

脚本注释

单行注释 #

多行注释

<<'EOF'
语句1
语句2
...
语句n
EOF

: 'comment line1
comment line2
more comments'

脚本构成

主脚本
模块(子脚本)

  • 主脚本 调用模块
  • 模块中 有 函数
  • 先调用模块,再调用函数

脚本执行参数

  • -x 将执行的脚本内容及输出显示到屏幕上
  • -n 不会执行该脚本,仅查询脚本语法是否有问题,并给出错误提示。
  • -v 在执行脚本时,先将脚本的内容输出到屏幕上然后执行脚本,如果有错误,也会给出错误提示

变量

变量类型

自定义变量

1.定义变量 变量名=变量值 ,变量名由字母、数字、下划线组成,必须以字母或下划线开头
2.引用变量 $变量名 或 ${变量名}
3.set显示所有变量,包括自定义变量和环境变量
4.取消变量unset 变量名 作用范围:仅在当前 shell 中有效

变量设置默认值

: ${VAR:=DEFAULT}

系统环境变量

1.定义环境变量 export export 变量 ,将自定义变量转换成环境变量
2.引用环境变量 $变量名 或 ${变量名}
3.env 显示所有环境变量
4.取消环境变量 unset 变量名
5.作用范围在当前shell和子shell有效

位置参数变量

$1 
$2 
$3
${10}

预先定义变量

$0 脚本文件名
$* 所有的参数 
$@  所有的参数
set  "I am" handsome oldboy
for i in "$*" ; do echo $i; done
for i in "$@" ; do echo $i; done
$#  参数的个数
$$  当前进程的 PID
$! 上一个后台进程的 PID
$? 上一个命令的返回值 0 表示成功
$_   在此之前执行的命令或脚本的最后一个参数

变量赋值方式

1.显式赋值(变量名=变量值)
2.read从键盘读入变量值

read -p "请输入数字:"
echo $REPLY

3.定义或引用变量时注意事项: " "弱引用 ’ '强引用
4.``命令替换等价于$()反引号中的shell命令会被先执行

变量扩展

变量长度

${#string}

从前往后删除变量内容

${string#substring} 从变量$string开头开始删除最短匹配$substring子串
${string##substring} 从变量$string开头开始删除最长匹配$substring子串

从后往前删除变量内容

${string%substring} 从变量$string结尾开始删除最短匹配$substring子串
${string%%substring} 从变量$string结尾开始删除最长匹配$substring子串

索引及切片

${VAR:位置:长度}

位置

  • 正数 0-max
  • 负数 min-1

长度

  • 正数 :长度
  • 负数 : 位置 (顾头不顾尾)
${string:position}$string中,从$position个开始提取子串(从0开始计数)
${string:position:length}$string中,从位置$position之后开始提取长度为$length的子串
符号含义
${VAR:OFFSET:-OFFSET}从开头删除N个字符,从结尾删除N个字符
${VAR:OFFSET}变量中删除从第一个字符到第N个字符
${VAR::-OFFSET}变量中从最后一个字符开始删除N个字符
${VAR::OFFSET}变量中从第一个字符开始获取N个字符
${VAR:(-OFFSET)}变量中获取从倒数第N个字符到最后一个字符

变量内容替换

${parameter/pattern/string} 使用string代替第一个匹配的pattern
${parameter//pattern/string} 使用string代替所有的pattern
${parameter/#pattern/string} 从开头匹配string变量中的pattern, 用string替换匹配的pattern
${parameter/%pattern/string} 从结尾匹配string变量中的pattern, 用string替换匹配的pattern

注: export LANG=C

变量内容大小写转换

符号含义
${VAR^}第一个字符大写
${VAR^^}所有字符大写
${VAR,}第一个字符小写
${VAR,,}所有字符小写
${VAR~}第一个字符的大小写相互转换
${VAR~~}所有字符的大小写相互转换

变量替代

符号含义
${VAR:-STRING}如果VAR为空或未设置,则将STRING其用作值
${VAR-STRING}如果VAR未设置,则将STRING其用作值
符号含义
${VAR:=STRING}如果VAR为空或未设置,请将的值设置VAR为STRING
${VAR=STRING}如果VAR未设置,请将的值设置VAR为STRING
符号含义
${VAR:+STRING}如果VAR不为空,则将STRING其用作值
${VAR+STRING}如果VAR设置为,则将STRING其用作值
符号含义
${VAR:?STRING}如果为空或未设置,则显示错误
${VAR?STRING}如果未设置,则显示错误

变量作用域

环境变量

使用 export 定义,在当前shell及其子shell中生效

本地变量

仅在当前shell中生效

局部变量

使用 local 定义 ,仅在函数中生效


表达式

运算符

++ – 自增 自减

    • ! ~ 正号 负号 逻辑取反 按位取反
  • / % 乘 除 取余
    • 加 减
      < <= > >= 比较符号
      == != 等于 不等于
      << >> 左移 右移
      & | ^ 按位与 按位或 按位异或
      && || 逻辑与 逻辑或
      ?: 条件表达式
      = += -= *= /= %= &= |= ^= <<= >>= 各种赋值运算符
      ** 幂运算

算术运算(整数)

[] test(()) [[]]
-eq== 或 =
-ne!=
-gt>
-ge>=
-lt<
-le<=

表达式符号

[ ]
[[ ]]
(( )) 仅用于整数

((1<2&&1>3))
((1<2||1>3))

算术运算(小数)

# a=1.2
# b=3
# echo "$a<$b" |bc
1
# echo "$a>$b" |bc
0
# echo "$a+$b" |bc
4.2
# x=$(echo "$a+$b" |bc)
# echo $x
4.2

逻辑运算

[] test[[]]说明
-a&&and 与
-o||or 或
!!not 非

字符串运算

-z "str" 若串长度为0则真,-z 可以理解为zero
-n "str"  若串长度不为0则真,-n可以理解为no zero
"str1"  =  "str2" 若串1等于串2则真,可以使用  "==" 代替  "="
"str1"  !=  "str2" 若串1不等于串2则真
"str1" =~ "pattern" 字符串匹配成功则为真 [[ ]]

文件测试

[ -f 文件 ] 文件存在且为普通文件则真,条件表达式成立
[ -d 目录 ] 目录存在且为目录文件则真,条件表达式成立
[ -s 文件 ] 文件存在且文件大小不为0则真,条件表达式成立
[ -e 文件 ] 文件存在则真,只要有文件就行
[ -r 文件 ] 文件存在且可读则真,条件表达式成立
[ -w 文件 ] 文件存在且可写则真,条件表达式成立
[ -L 文件 ] 文件存在且为链接文件则真,条件表达式成立
[ f1 -nt f2 ] 文件f1比文件f2新则真,条件表达式成立
[ f1 -ot f2 ] 文件f1比文件f2旧则真,条件表达式成立

流程控制

  • 顺序
  • 选择
  • 循环

表达式

表达式的值作为条件时只有真和假

  • 真(true | 非0 | 非空 | 条件成立 | $?为0(此条shell特有))
  • 假(false | 0 | 空 | 条件不成立 | $?不为0(此条shell特有))

此规则适用于所有的计算机高级语言

算术运算
逻辑运算
Linux命令

选择(分支)

if

if 条件表达式;then
  命令
fi
#/bin/bash
http="ss -lntup|grep nginx &> /dev/null"
if eval $http
then
  echo 1
else
  echo 0
fi

流程图

Created with Raphaël 2.3.0 Start 条件表达式为真? 命令1 End yes no

if else

if 条件表达式;then
  命令1
else
  命令2
fi
Created with Raphaël 2.3.0 Start 条件表达式为真? 命令1 End 命令2 yes no

示例

expr $OPTION + 1 > /dev/null 2>&1
if [ $? -ne 0 ]; then
    :
else
    :
fi

if elif else

if 条件表达式;then
  命令1
elif 条件表达式2;then
  命令2
else
  命令3
fi
Created with Raphaël 2.3.0 Start 条件表达式为真? 命令1 End 条件表达式2为真? 命令2 命令3 yes no yes no

case

case 模式名 in
  模式1)
    命令1
    ;;
  模式2)
    命令2
    ;;
  模式3)
    命令3
    ;;
  *)
    其它命令
esac
Created with Raphaël 2.3.0 Start 模式名 模式名==模式1 ? 命令1 End 模式名==模式2 ? 命令2 模式名==模式3 ? 命令3 其它命令 yes no yes no yes no

循环

for

for 变量名 in 取值列表
do
  命令
done


for ((expr1;expr2;expr3))
do
  命令
done

expr1 初值
expr2 终值
expr3 步长值

Created with Raphaël 2.3.0 Start expr1 expr2为真 ? 命令 expr3 End yes no

IFS

#!/bin/bash
data='a,b,c,d'
IFS=,
for i in $data;do
  echo $i
done

while

while 条件表达式
do
  命令
done
Created with Raphaël 2.3.0 Start 条件表达式为真 ? 命令 End yes no

把a.txt文件中的内容倒腾到b.txt文件中

cat a.txt
1
2
3
4
5
6
7
8
9
10

cat b.txt
10
9
8
7
6
5
4
3
2
1

#!/bin/bash
touch b.txt

while [ -n "$(cat a.txt)" ]
do
	if [ -z "$(cat b.txt)" ];then
		head -1 a.txt > b.txt
        else
		sed -i "1i `head -1 a.txt`" b.txt
        fi
	sed -i 1d a.txt

done

while read

while read -p "请输入:"
do
  if [[ $REPLY =~ ^[0-9]+$ ]];then
    echo "输出:$((REPLY*=${REPLY}00))"
  elif [[ "$REPLY" = "q" ]];then
    break
  fi
done

while读取文件三种方式

1cat ./a.txt | while read LINE
do
  echo $LINE
done

2while read LINE
do
  echo $LINE
done < ./a.txt

3exec < ./a.txt
while read LINE
do
  echo $LINE
done

break

break n 表示跳出循环的层数
省略n 表示跳出整个循环

continue

continue n 退到第n层继续循环
省略n 表示跳出本次循环,继续下一次循环

select

#PS3=[$USER@$0]#
select VAR in var1 var2 quit
do
  case $VAR in
  var1)
    cmd1
    ;;
  var2)
    cmd2
    ;;
  quit)
    break
  esac
done

函数

函数定义

function 函数名(){
  命令
}

函数参数

$1
$2
$3
$#
$*
$@

函数调用

函数名 参数1 参数2 参数3

函数返回

  • 返回数字作为函数执行状态 返回给$? 取值范围 0-255 (使用 return)
  • 返回数字作为函数执行结果 (使用 echo)
  • 返回字符串,作为函数执行结果 (使用 echo)

系统函数库

系统函数库

/etc/init.d/functions

action函数

action “xxxxx” /bin/true
action “xxxxx” /bin/false

功能函数库

# 脚本初始化
function scripts_init(){
  prog=`basename $0 .sh`
  LockFile=/var/lock/subsys/${prog}.lock  # 使用锁文件
  LogFile=/var/log/${prog}.log  # 脚本记录日志
  PidFile=/var/run/${prog}.pid  # 记录进程号,可以管理脚本

  [ -f $LockFile ] && echo "There $LockFile is exist!!" && exit 1 ||touch $LockFile
  [ ! -f $LogFile ] && touch $LogFile
  [ -f $PidFile ] && echo "There $PidFile is exist!!" && exit 2|| echo $$ > $PidFile
}

# 记录日志
function writelog(){
  Date=$(date "+%F_%T")
  ShellName=`basename $0`
  Info=$1
  echo "$Date : ${ShellName} : ${Info}" >> ${LogFile}
}

# 脚本退出扫尾
function closeout(){
  [ -f $LockFile ] && rm -f $LockFile 
  [ -f $PidFile ]&& rm -f $PidFile
}

# 判断输入是整数
function int_judge(){
  fun_a=$1
  expr $fun_a + 1 &>/dev/null
  RETVAL=$?
  return $RETVAL
}

# 判断输入非空
function input_judge(){
  RETVAL=0
  fun_a=$1
  [ ${#fun_a} -eq 0 ]&& RETVAL=1
  return $RETVAL
}

数组

  • 数组名代表首地址

下标是从0开始的整数

普通数组(索引数组)

定义数组

array=(a b c)

获取所有元素

${array[*]}

获取元素下标

${!a[@]}

获取数组长度

${#array[*]}

获取一个元素的长度

${#name[0]}

获取第一个元素

${array[0]}

获取第二个元素

${array[1]}

获取多个元素

array=(1 2 3 4 5)
echo ${array[@]:1}
2 3 4 5

#array[@]:下标:截取元素个数
echo ${array[@]:1:3}
2 3 4

添加元素

array[3]=d

添加多个元素

array+=(e f g)

删除第一个元素

unset array[0]    # 删除会保留元素下标

删除数组

unset array

数组切片

${name[4]:0:7}

关联数组

关联数组的下标是字符串

定义关联数组

declare -A M

关联数组赋值

M=([a]=11 [b]=22)

获取关联数组元素

echo ${M[a]}
11

获取关联数组元素个数

echo ${#M[@]}
2

获取关联数组下标

echo ${!M[*]}
a b

获取关联数组所有元素

echo ${M[@]}
11 22

添加元素

M[c]=33

添加多个元素

M+=([d]=33 [e]=44)

编程小题目

1、编写一个脚本,实现任意个数的加法

#!/bin/bash
for i in  $@
do
  sum=$((sum+i))
done
echo $sum

获取脚本的绝对路径

[root@node1 init.d]# pwd
/etc/init.d
[root@node1 init.d]# ll
总用量 40
-rw-r--r--. 1 root root 18281 522 2020 functions
-rwxr-xr-x. 1 root root  4569 522 2020 netconsole
-rwxr-xr-x. 1 root root  7928 522 2020 network
-rw-r--r--. 1 root root  1160 102 2020 README
[root@node1 init.d]# dirname $(readlink -f network)
/etc/rc.d/init.d
SHELL_DIR="$(dirname $(readlink -f "$0"))"
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wuxingge

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值