你还不会shell脚本吗,我来教你

二十一

这几天也是刚学习了shell脚本的编写,虽然他不像Python、Java那样能够编写很大型的项目(当然我是这么认为),但是在操控Linux系统方面,还是有独特的优势的,当然在学习过程中我们也能更好的了解Linux。接下来,就开始学习吧。后面会有几个小例子,当然都是别的地方挪过来的,我就是代码的搬运工,嘿嘿。喜欢学习的同志们可以点击Python聚焦专栏,查看更多知识。

繁琐的括号总结

基本概念

解释器种类

  • Bourne Shell(/usr/bin/sh或/bin/sh)
  • Bourne Again Shell(/bin/bash)
  • C Shell(/usr/bin/csh)
  • K Shell(/usr/bin/ksh)
  • Shell for Root(/sbin/sh)

在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash。

脚本编写

  • 指定使用的解释器类型
#!/bin/bash 

运行方式

作为可执行程序

chmod +x ./test.sh # 修改权限
./test.sh   # 执行

运行时一定要写成./test.sh,因为直接写test.sh,linux会去PATH里寻找,而一般只有/bin,/sbin,/usr/bin,/usr/sbin等在PATH中,所以使用./test.sh告诉系统,就在本目录下找

作为解释器参数

  • 这种方式可以不用在sh文件中写明解释器类型,写了也是没有用的
/bin/sh test.sh

基本语法

变量

  • 定义方式和python类似,只不过定义过程中不允许使用空格,默认都是字符串类型

    • declare命令定义有类型的变量

      • -i : 定义整型变量
      • -a : 定义一个数组
      • -f : 查看系统中所有定义的函数
      • -F : 查看系统中所有定义的函数名称
      • -x : 声明一个环境变量--在脚本文件中可以直接使用的变量
      • 取消定义的变量:把命令减号改成加号再执行
  • 使用时只需要使用$ / ${ }就可以了
  • 只读变量:在变量定义后,再使用readonly 修饰,再次赋值会报错
  • 删除变量:unset var_name,不能删除只读变量

变量数据修改

语法 说明
${var_name#规则} 从变量开头进行匹配,将符合最短的数据删除
${var_name##规则} 从变量开头进行匹配,将符合最长的数据删除
${var_name%规则} 从变量末尾进行匹配,将符合最短的数据删除
${var_name%%规则} 从变量末尾进行匹配,将符合最长的数据删除
${变量名/旧字符串/新字符串} 变量内容符合旧字符串,就将第一个替换
${变量名//旧字符串/新字符串} 变量内容符合旧字符串,就全部替换

字符串

  • Shell字符串

    • 单引号:不能使用变量
    • 双引号:可以使用变量,并转义\n等字符
    • 反引号:用于保存要执行的命令,同:$() 【点击例子】
    • 在进行拼接的时候是可以出现以下形式的:

      • "Hello, "$world""
      • 'Hello, '$world''
  • expr命令是从1开始索引,而普通的提取都是从零开始索引的
  • 求长度

    • 获取字符串长度:$#var_name
    • ${#str}
    • expr lenth $str
  • 求字串索引

    • expr index $str substr_reg

      • substr其实索引的是其每个字符,返回最小索引的那个
  • 匹配的字串的长度

    • expr match $str substr_reg
  • 截取

    • ${str:start}
    • ${str:start:lenth}
    • ${str:(start)}/\${str: -start} start为负数,表示从尾部开始
    • expr substr $str $start $length

数组

  • 定义:

    • array_name=(value0 value1 value2 value3) 使用空格分隔元素
    • array_name[0]=value0 / array_name[1]=value1下标可以不连续
  • 读取:

    • 单个读取:${array_name[index]}
    • 全部读取:${array_name[@]}
    • 获取长度:

      • 数组长度:length=${#array_name[@]}/length=${#array_name[*]}
      • 单个元素长度:lengthn=${#array_name[n]}

注释

  • 单行:#
  • 多行:

    • :<<EOF . . . EOF
    • 使用其他符号替代EOF,如:'

函数

  • 定义

    • function func_name { }
    • func_name ( ) { }
  • 返回值

    • return : 一般返回一个整数,用于做判断
    • echo : 用于返回数据
    • printf
  • 局部变量

    • local修饰,不进行修饰那么函数执行后,其他地方也可以使用。
  • 函数库

    • 文件后缀是任意的,一般为lib
    • 一般不会赋予可执行权限
    • 第一行一般使用#!/bin/echo输出警告信息,避免用户执行

获取命令行参数

  • $num:num为要获取的参数位置,从0开始,分别代表文件名,参数1,参数2
  • $#:传递到脚本的参数个数
  • &dollar;&dollar;:脚本运行的当前进程ID号
  • $!:后台运行的最后一个进程的ID号
  • $?:显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
  • $-:显示Shell使用的当前选项,与set命令功能相同。
  • $* / $@:以一个单字符串显示所有向脚本传递的参数。

    • 相同点:都是引用所有参数。
    • 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。

中括号的使用(一般可以使用test命令替换)

  • 一个变量是否为0, [ $var -eq 0 ]

    • ne:不等于
    • lt/gt:小于/大于
    • le/ge:小于等于/大于等于
  • 一个文件是否存在,[ -e $var ], 是否是目录,[ -d $var ]
  • 两个字符串是否相同, [[ $var1 = $var2 ]]
  • -a/-o:and/or
  • -e : exist
  • -r : 是否可读
  • -w : 是否可写
  • -n :判断字符串长度是否非0
  • -z :判断字符串长度是否为0
  • $ :判断字符串是否非空

运算符:原生bash不支持简单的数学运算,需要使用awk和expr,expr最常用,并且只能进行整数运算

  • 表达式和运算符之间要有空格
  • 完整的表达式要被 包含
  • 带有转移的字符需要使用\修饰才能使用
  • 使用$(())中间的运算符不需要转义并且不要求有空格,不能进行相等和不等的判断
  •   echo `expr 2 + 2` # 输出4
  • 成立返回1,不成立返回0
  • 在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 "*" 不需要转义符号 ""
  • 浮点数计算:bc

    • echo "scale=2;1+1.2" | bc

几个常用命令

  • read命令

    • 从标准输入中接收一行,并对修饰的变量赋值
    • read -p "请输入一段文字:" -n 6 -t 5 -s password

      • -p 输入提示文字
      • -n 输入字符长度限制(达到6位,自动结束)
      • -t 输入限时
      • -s 隐藏输入内容
  • echo

    • -e 开启转义,对字符串中的转义字符进行转义操作,不区分单双引号
  • printf

    • printf "%s" jim
  • test:一般用于替换中括号

    • test $num = $num2

流程控制

  • if . . . else

    • if condition
      then
          command1 
      elif condition1
      then
          command2
      else
          commandN
      fi
  • for . . . in

    • for var in data
      do
          command1
      done
  • while

    • while condition
      do
          command
      done
  • until:与while相反操作,条件为true时退出循环
  • 死循环

    • while :
      do
          command
      done
      # 使用true
      while true
      do
          command
      done
      # 使用for
      for (( ; ; ))
  • case

    • case value in
      value1)
          command1
      ;;
      value2)
          command2
      ;;
      *)
          command2
      ;;
      esac

let执行一个或多个表达式

sed(Stream Editor)命令详解,对查找到的数据进行处理【点击例子】

# 语法格式:
sed [option] "pattern command" file_name
# 删除文件第一行
sed -i '1d' file_name
  • option选项

    • n:只输出匹配的行
    • e:需要匹配的条件,可以指定多个-e "pattern command"
    • f:指定sed文件,用于封装替换"pattern command"
    • r:用于支持正则表达式
    • 修改输出内容:sed -n 's/love/like/g;p' sed.txt
    • i:修改源文件
  • pattern

    • 可以使用正则表达式
    • 可以使用变量,只要按照脚本使用变量就可以:双引号,$var_name
    • 匹配/需要进行转义
    • 按行匹配的时候,行数在后面如果小于前一个匹配模式,那么久只显示满足前一个条件的行
    • =:显示行号
  • command

    • a : 在匹配到行的下一行添加字符串
    • i :在匹配到行的上一行添加字符串
    • r :在匹配到行的下一行添加file内容
    • w :将匹配到的行写入文件
    • d :删除数据
    • p :打印数据
    • g :修改数据时全部匹配,3g表示从第三个开始全部修改,ig忽略大小写
    • = :显示匹配到的行号
  • 反向引用

    • 在使用替换字符的时候,修改内容使用&表示使用被替换的条件

      • # 在匹配到^la..jim的后面加shuai
        # &:全匹配,\1:其使用了正则的分组,所以前面需要使用小括号括起来
        sed -i 's/^la..jim/&shuai/g' sed.txt
  • 命令详解

awk工作模式【点击例子】

# 语法格式:
awk 'BEGIN{}pattern{commands}END{}' file_name

小例子

  • <span id="find_user_all">查询所有用户</span>
for user in `cat /etc/passwd | cut -d ":" -f 1`
do
    echo "$user"
done
  • <span id="start_nginx">启动nginx</span>
nginx_num_process=$(ps -ef | grep nginx | grep -v grep | wc -l)
if [ nginx_num_process -eq 0 ];then
    systemctl start nginx
fi
  • <span id="num_add">用户输入num,求1-num之和</span>
while true
do
    read -p "pls input a positive number: " num
    expr $num + 1 &> /dev/null
    if [ $? -eq 0 ];then
        if [ `expr $num \> 0` -eq 1 ];then
            for((i=1;i<=$num;i++))
            do
                sum=`expr $sum + $i`
            done    
            echo "1+2+3+....+$num = $sum"
            exit
        fi
    fi
    echo "error,input enlegal"
    continue
done
  • <span id="check_nginx">检查Nginx是否正常运行,宕机则启动它</span>
this_pid=$$

while true
do
ps -ef | grep nginx | grep -v grep | grep -v $this_pid &> /dev/null

if [ $? -eq 0 ];then
    echo "Nginx is running well"
    sleep 3
else
    systemctl start nginx
    echo "Nginx is down,Start it...."
fi
done
  • <span id="find_mysql">查找mysql配置文件中有几段</span>
FILE_NAME=/root/lesson/5.6/my.cnf
function get_all_segments
{
    echo "`sed -n '/\[.*\]/p' $FILE_NAME  | sed -e 's/\[//g' -e 's/\]//g'`"
}
function count_items_in_segment
{
    items=`sed -n '/\['$1'\]/,/\[.*\]/p' $FILE_NAME | grep -v "^#" | grep -v "^$" | grep -v "\[.*\]"`
    index=0
    for item in $items
    do
        index=`expr $index + 1`
    done
    echo $index
}
number=0
for segment in `get_all_segments`
do
    number=`expr $number + 1`
    items_count=`count_items_in_segment $segment`
    echo "$number: $segment  $items_count"
done
  • <span id="del_blank">删除配置文件中所有的注释行和空行</span>
sed -i '/[:blank:]*#/^$/d' config.cnf
  • <span id="add_not_ano">在非#注释行前加*</span>
sed -i 's/^[^#]/\*&/g' config.cnf
  • <span id="text_insert_mysql">文本格式化数据插入mysql</span>
user=""
password=""
host=""
mysql_conn="mysql -u"$user" -p"$password" -h"$host""
IFS=":" # 内置分隔符变量
cat data.txt | while read id name birth sex
do
  $mysql_conn -e "insert into school values('$id','$name','$birth','$sex')"
done
  • <span id="script_use_ftp">脚本使用ftp</span>
ftp -inv << EOF
open ftp_ip_addr
user user_name password

put file_name
bye
EOF #必须顶格写

小东东

  • nohub + & 后台启动 : nohub不间断的运行程序,关闭窗口也不会关闭进程,&用于后台运行
  • netstat -tnlp | grep port : 一般用于查看端口
  • &&当左侧的命令返回0(成功)才会执行右侧命令
  • cut -d ":"制定分隔符
  • free -m:内存使用情况
  • df -h:磁盘使用情况
  • n >& m:将输出文件 m 和 n 合并
  • n <& m:将输入文件 m 和 n 合并
  • << tag:将开始标记 tag 和结束标记 tag 之间的内容作为输入
  • grep -E等同于egrep,用于扩展支持正则表达式
  • cat -n file显示行号输出
  • /sbin/nologin 不可以登陆的用户
  • [:blank:]表示空格
  • ^$表示空行
  • sh -x可以查看执行过程
  • 根据其他表的结构创建新表

    • create table new_table like other_table
  • mysql -B不显示边框 -E表示垂直显示 -H输出html -X输出xml -N不显示列名
  • mysqldumps备份mysql

    • d :只导出表结构
    • t :只导出数据,不导出建表语句
    • A :导出所有数据库
    • B :导出一个或者多个数据库
  • crontab定时任务
阅读 1.3k

Python聚焦
不断去记录学习python及python项目中的用到的知识点。

无论遇到多大的困难,你总是能扛过去,坚持一件事,对自己

1.4k 声望
234 粉丝
0 条评论

无论遇到多大的困难,你总是能扛过去,坚持一件事,对自己

1.4k 声望
234 粉丝
宣传栏