SHELL 编程


shell 编程

变量赋值

  • 变量赋值的几种方式

    1. 变量=数值
    2. 引用其他命令结果进行赋值 ip=`ps -ef|grep "mysql"`
    3. 交互式变量赋值 read -t设置超时时间 -s不显示输入信息(密码) -p 设置提示信息 #这里-t建议放最前面,放后面可能不生效
    4. 脚本位置参数传参 $1 $2 $3
  • shell编程默认赋值都是字符串,所以单引号 双引号 或者直接字符串都一样

    [root@127 download]# name=test
    [root@127 download]# name1="test1"
    [root@127 download]# name2='test2'
    [root@127 download]# echo $name1
    test1
    [root@127 download]# echo $name2
    test2
    [root@127 download]# echo $name
    test
    [root@127 download]#
    
    
  • 单引号变量,不识别特殊语法,双引号变量,可以识别特殊语法,反引号中的命令结果会被保留下来

    [root@127 download]# name=test
    [root@127 download]# name1="test1"
    [root@127 download]# name2='test2'
    # 双引号可以识别$变量名的用法,单引号不行
    [root@127 download]# echo "$name1"
    test1
    [root@127 download]# echo "$name"
    test
    [root@127 download]# echo "$name2"
    test2
    [root@127 download]# echo '$name2'
    $name2
    [root@127 download]# echo '$name1'
    $name1
    [root@127 download]# echo '$name'
    $name
    # 反引号
    [root@127 download]# test=`ls -ll`
    [root@127 download]# echo $test
    total 82644 drwxr-xr-x 17 501 501 4096 Mar 11 15:52 Python-3.6.12 -rw-r--r-- 1 root root 84623360 Aug 15 2020 Python-3.6.12.tar
    
    
  • 位置变量

    $*和$@的区别,当$*和$@ 不被" "包围时,没什么区别,都是将接受的每个参数看成一份整体数据,彼此用空格间隔而已.
    如果被" "包围,$* 还是把所有接受的数据当成一份数据, 而$@ 会把每份数据单独视为一份数据,彼此间是独立的
    比如bash text.bash alex 180  "$@" 接受的参数是alex和180 而$* 接受的参数是"alex 180"
    
    #! /bin/bash
    echo '特殊变量$0 $1 $2的实践'
    echo '结果 : '$0 $1 $2 
    
    echo "##############################"
    echo '特殊变量$#的实践'
    echo '结果 : '$#
    
    echo "##############################"
    echo '特殊变量$*和$@的实践'
    echo '结果 : '$*
    echo "##############################"
    echo '结果 : '$@
    
    把下面保存为1.sh,运行结果如下
    [root@django_env2 ~]# bash 1.sh alex 180
    特殊变量$0 $1 $2的实践
    结果 : 1.sh alex 180
    ##############################
    特殊变量$#的实践
    结果 : 2
    ##############################
    特殊变量$*和$@的实践
    结果 : alex 180
    ##############################
    结果 : alex 180
    
    把下面保存为2.sh
    #! /bin/bash
    echo '打印\"\$*\"'
    for var in "$*"
    do
    	echo "$var"
    done
    echo "#############"
    echo '打印\"\$@\"'
    for var in "$@"
    do
    	echo "$var"
    done
    
    运行结果如下
    [root@django_env2 ~]# bash 2.sh alex 180
    打印\"\$*\"
    alex 180
    #############
    打印\"\$@\"
    alex
    180
    
  • 变量子串 截取,基础${#args} ${args} 截取${args:start:length} 删除${args#word} ${args%word} 替换${args/找谁/替换}

    用test=congratulation示例
    ${变量}			返回变量值
    ${#变量}			返回变量长度,字符长度 
    计算字符串长度其他方法还有wc -l 比如cat 1.txt |wc -L #打印最长行数的字符串长度
    还有expr length "$test"和awk的echo "$test" |awk '{print length($0)}'
    
    ${变量:start}		返回变量offset数值后的长度 echo ${test:2}>>ngratulation
    ${变量:start:length}提取offset之后的length限制的字符 echo ${test:2:3}>>ngr
    
    无论是从后向前还是从前向后,匹配的字符串支持* ? 等通配符
    而且匹配位置不支持字符串中间,必须是以XXX为开始或者XXX为结束才能匹配到
    ${变量#word}		从变量开头删除最短匹配的word子串
    比如a=abc123abc  ${a#ab} >>c123abc
    ${变量##word}		从变量开头删除最长匹配的word
    比如a=abc123abc  ${a##a*c} >>  因为##匹配的是最长abc123abc
    ${变量%word}		从变量结尾删除最短匹配的word子串
    ${变量%%word}		从变量结尾删除最长匹配的word
    ${变量/pattern/string}	用string代替第一个匹配的pattern
    ${变量//pattern/string}	用string代替所有的的pattern
    
    [root@localhost ~]# a="man man boy boy man"
    [root@localhost ~]# echo ${a/man/girl}
    girl man boy boy man
    [root@localhost ~]# echo ${a//man/girl}
    girl girl boy boy girl
    
    

    示例,来一个批量修改文件名的操作

    touch test{1..5}.jpg  >>> test1.jpg  test2.jpg  test3.jpg  test4.jpg  test5.jpg  先批量创建5个jpg文件
    
    for i in `ls *.jpg`
    do mv $i `echo ${i/test/best}`
    done
    

    变量扩展用法 对于变量的值进行判断和处理

    如果parameter变量为空,返回word字符串
    ${parameter:-word}
    
    如果parameter变量为空,则word代替变量并返回其值
    这里如果parameter为空,则ret和parameter都为word的值
    ret=${parameter:=word}
    
    如果parameter变量为空,word当做stderr说粗话,否则输出变量值
    ${parameter:?word}
    
    如果parameter变量为空,什么都不做,如果不为空则返回word
    ${parameter:+word}
    

    示例,比如把这个对变量判断添加到find命令中,提高容错率

    find ${dir_path:=/opt/mysql/} -name "*.tar" -type f -mtime +7

    表示状态的变量

      $?   上一条命令/脚本返回值  0正常  非0失败  用来判断执行是否成功
      $$    当前运行脚本的pid,把pid记录到文件中用来kill
      $!    上一个运行脚本的pid
      $_    上一个脚本或命令的最后一个参数 和esc+.一样
    

环境变量设置

环境变量一般指用export内置命令导出的变量,用于定义shell的运行环境

  • 用户个人配置文件 ~/.bash_profile, ~/.bashrc 远程登陆用户特有文件
  • 全局配置文件/etc/profile /etc/bashrc,且系统建议最好创建在/etc/profile.d/而不是直接修改主文件,全局配置文件,影响所有登陆系统的用户
  • set 和declare 输出所有变量,包括全局变量和局部变量
  • env 只显示全局变量
  • unset 变量名,删除变量或者函数
  • export 显示和设置环境变量值
  • readonly 设置变量只对当前shell生效. readonly name=test

环境变量文件加载顺序

bash一些基础的内置命令

  • echo
-n 不换行输出
-e 解析字符串中的下面特殊字符
    \n 换行
    \r 回车
    \t tab
    \b 应使用字符之前或之间, 字符尾部跟\b 是没有效果的最前面使用 删除后面紧跟的字符,之间使用删除前一个字符
echo -e " \b哇\b哈哈"
 哈哈

  • eval

    把参数传给他,然后当命令执行 eval "cd /opt; ls -ll"

  • exec

    不创建子进程,执行后续命令,且执行完毕后自动exit,下面就是执行date命令后退出了root账号

    [root@django_env2 ~]# exec date
    2022年 04月 06日 星期三 07:29:25 CST
    
    ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    
    Session stopped
        - Press  to exit tab
        - Press R to restart session
        - Press S to save terminal output to file
    
    

进程列表和子shell环境

shell的进程列表理念,要用到小括号() cd ~;ls;

检测是否在子shell环境中,输出BASH_SUBSHELL变量,如果是0,表示在当前shell环境,否则就是子shell运行的命令

一个小括号开启的是一个子shell命令(cd ~;ls;echo $BASH_SUBSHELL)

子shell嵌套运行

利用子shell,可以实现多进程的处理,提高程序并发执行效率.

比如运行(ls;echo $BASH_SUBSHELL;(cd /var;ls;echo $BASH_SUBSHELL))

运行结果

download  nodejs860  ossutil  python362  python_virtualenvwrapper  redis-6.0.16  rh  stunnel
1
account  adm  cache  crash  data  db  empty  games  gopher  kerberos  lib  local  lock  log  mail  nis  opt  preserve  run  spool  tmp  www  yp
2  # 代表第二个子shell

for循环

语法 for 变量 in 序列1~100    示例: for number in {1..100}
do  放循环体语句			   do echo number
done 结束for循环			   done

if 判断

if后面要有空格,且[后面、]前面都要有空格,然后是分号,最后是then
里面有多个条件判断 -eq(equal) 相等 -ne(inequality) 不相等 -gt(greater than) 大于 -lt(less than) 小于 -ge(greater equal) 大于或等于 -le(less equal) 小于或等于

语法:
if [  $? == 0  ];then  #==也可以用-eq代替
    执行脚本
fi

shell示例
用shell写一个简单的脚本,用ping探测域名是否会响应

#!/bin/bash
url=$1
ping -c2 -i0.2 -W0.5 $url >/dev/null 2>&1  # -c是ping的次数 -W是timeout -i是间隔时间
if [ $? -eq 0 ];then
	echo "$url 正常"
else
	echo "$url 不正常"
fi