zoukankan      html  css  js  c++  java
  • 别人的Linux私房菜(13)学习Shell脚本

    CentOS6.x以前版本的系统服务启动接口在/etc/init.d/目录下,存放了脚本。

    Shell脚本因调用外部命令和bash 的一些默认工具,速度较慢,不适合处理大量运算。

    执行方式有:直接命令执行、绝对路径/相对路径执行、PATH执行、bash程序执行。

    PATH中含有家目录的bin路径,可以在bin下写的脚本直接执行。

    sh file

    #!/bin/bash加载环境相关的配置文件,一般指代非登录的~/.bashrc

    输入姓名并输出:

    1 read -p "Please input your first name: " firstname  # 提示使用者输入
    2 read -p "Please input your last name:  " lastname   # 提示使用者输入
    3 echo -e "
    Your full name is: $firstname $lastname" # 结果由萤幕输出
    View Code

    建立以前天,昨天,今天有关的文件名:

     1 echo -e "I will use 'touch' command to create 3 files." # 纯粹显示资讯
     2 read -p "Please input your filename: " fileuser         # 提示使用者输入
     3 
     4 # 2. 为了避免使用者随意按 Enter ,利用变量功能分析档名是否有配置?
     5 filename=${fileuser:-"filename"}           # 开始判断有否配置档名
     6 
     7 # 3. 开始利用 date 命令来取得所需要的档名了;
     8 date1=$(date --date='2 days ago' +%Y%m%d)  # 前两天的日期
     9 date2=$(date --date='1 days ago' +%Y%m%d)  # 前一天的日期
    10 date3=$(date +%Y%m%d)                      # 今天的日期
    11 file1=${filename}${date1}                  # 底下三行在配置档名
    12 file2=${filename}${date2}
    13 file3=${filename}${date3}
    14 
    15 # 4. 将档名创建吧!
    16 touch "$file1"                             # 底下三行在创建文件
    17 touch "$file2"
    18 touch "$file3"
    View Code

    简单加减乘除:

    1 echo -e "You SHOULD input 2 numbers, I will cross them! 
    "
    2 read -p "first number:  " firstnu
    3 read -p "second number: " secnu
    4 total=$(($firstnu*$secnu))
    5 echo -e "
    The result of $firstnu x $secnu is ==> $total"
    View Code

    求余运算示例:echo $(( 13 % 3 ))

    乘法运算的另一种方式:declare -i total=$firstnu*$secnu 

    计算含小数点的数据:echo "123.123*55.9" | bc

    计算π值:echo "scale=10; 4*a(1)" | bc -lq#调用了4*a(1)函数,计算π并取小数点后10位。

    直接执行的bash(绝对路径相对路径或PATH等),执行中的赋予新的子进程bash,使用子进程的bash配置,变量为局部变量。

    利用source 来执行的脚本,变量成为全局变量。

    test命令的测试功能:

    如 test -e /home && echo "ok" || echo "no"检查目录是否存在

    1. 关於某个档名的『文件类型』判断,如 test -e filename 表示存在否
    http://cn.linux.vbird.org/linux_basic/0340bashshell-scripts_3.php

    判断文件类型和权限:

     1 echo -e "Please input a filename, I will check the filename's type and 
     2 permission. 
    
    "
     3 read -p "Input a filename : " filename
     4 test -z $filename && echo "You MUST input a filename." && exit 0
     5 # 2. 判断文件是否存在?若不存在则显示信息并结束脚本
     6 test ! -e $filename && echo "The filename '$filename' DO NOT exist" && exit 0
     7 # 3. 开始判断文件类型与属性
     8 test -f $filename && filetype="regulare file"
     9 test -d $filename && filetype="directory"
    10 test -r $filename && perm="readable"
    11 test -w $filename && perm="$perm writable"
    12 test -x $filename && perm="$perm executable"
    13 # 4. 开始输出资讯!
    14 echo "The filename: $filename is a $filetype"
    15 echo "And the permissions are : $perm"
    View Code

    [ ] 判断符号

    [ ]两端需要空格分隔,每个组件空格分隔,变量双引号,常数,单引号或双引号,参数基本同test命令。=和==相同

    如检查变量是否为空:[ -z "$HOME" ] ; echo $?

     使用中括号进行的判定示例:

    1 read -p "Please input (Y/N): " yn
    2 [ "$yn" == "Y" -o "$yn" == "y" ] && echo "OK, continue" && exit 0
    3 [ "$yn" == "N" -o "$yn" == "n" ] && echo "Oh, interrupt!" && exit 0
    4 echo "I don't know what your choice is" && exit 0
    View Code

    shell脚本使用的默认变量:

    $0表示该脚本名,$1-$.......表示执行该脚本接入的命令参数

     $#接入的参数个数(除$0)     $@所有变量,$* 带分隔符的所有变量。

    示例:输入参数即可测试。

    1 echo "The script name is        ==> $0"
    2 echo "Total parameter number is ==> $#"
    3 [ "$#" -lt 2 ] && echo "The number of parameter is less than 2.  Stop here." 
    4     && exit 0
    5 echo "Your whole parameter is   ==> '$@'"
    6 echo "The 1st parameter         ==> $1"
    7 echo "The 2nd parameter         ==> $2"
    View Code

     shift:参数左偏移减少。示例如下:

    1 echo "Total parameter number is ==> $#"
    2 echo "Your whole parameter is   ==> '$@'"
    3 shift   # 进行第一次『一个变量的 shift4 echo "Total parameter number is ==> $#"
    5 echo "Your whole parameter is   ==> '$@'"
    6 shift 3 # 进行第二次『三个变量的 shift7 echo "Total parameter number is ==> $#"
    8 echo "Your whole parameter is   ==> '$@'"
    View Code

    使用if [];then   xxx fi 语句示例:

    && 等同 -a   ||  等同 -o

     1 read -p "Please input (Y/N): " yn
     2 
     3 if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then
     4     echo "OK, continue"
     5     exit 0
     6 fi
     7 if [ "$yn" == "N" ] || [ "$yn" == "n" ]; then
     8     echo "Oh, interrupt!"
     9     exit 0
    10 fi
    11 echo "I don't know what your choice is" && exit 0
    View Code
    1 read -p "Please input (Y/N): " yn
    2 
    3 if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then
    4     echo "OK, continue"
    5 elif [ "$yn" == "N" ] || [ "$yn" == "n" ]; then
    6     echo "Oh, interrupt!"
    7 else
    8     echo "I don't know what your choice is"
    9 fi
    View Code

    查看端口是否打开:•80: WWW    •22: ssh    •21: ftp     •25: mail

     1 testing=$(netstat -tuln | grep ":80 ")   # 侦测看 port 80 在否?
     2 if [ "$testing" != "" ]; then
     3     echo "WWW is running in your system."
     4 fi
     5 testing=$(netstat -tuln | grep ":22 ")   # 侦测看 port 22 在否?
     6 if [ "$testing" != "" ]; then
     7     echo "SSH is running in your system."
     8 fi
     9 testing=$(netstat -tuln | grep ":21 ")   # 侦测看 port 21 在否?
    10 if [ "$testing" != "" ]; then
    11     echo "FTP is running in your system."
    12 fi
    13 testing=$(netstat -tuln | grep ":25 ")   # 侦测看 port 25 在否?
    14 if [ "$testing" != "" ]; then
    15     echo "Mail is running in your system."
    16 fi
    View Code

    判断输入是否8个数字,并计算时间差的天数:

     1 echo "This program will try to calculate :"
     2 echo "How many days before your demobilization date..."
     3 read -p "Please input your demobilization date (YYYYMMDD ex>20090401): " date2
     4 
     5 # 2. 测试一下,这个输入的内容是否正确?利用正规表示法罗~
     6 date_d=$(echo $date2 |grep '[0-9]{8}')   # 看看是否有八个数字
     7 if [ "$date_d" == "" ]; then
     8     echo "You input the wrong date format...."
     9     exit 1
    10 fi
    11 
    12 # 3. 开始计算日期罗~
    13 declare -i date_dem=`date --date="$date2" +%s`    # 退伍日期秒数
    14 declare -i date_now=`date +%s`                    # 现在日期秒数
    15 declare -i date_total_s=$(($date_dem-$date_now))  # 剩余秒数统计
    16 declare -i date_d=$(($date_total_s/60/60/24))     # 转为日数
    17 if [ "$date_total_s" -lt "0" ]; then              # 判断是否已退伍
    18     echo "You had been demobilization before: " $((-1*$date_d)) " ago"
    19 else
    20     declare -i date_h=$(($(($date_total_s-$date_d*60*60*24))/60/60))
    21     echo "You will demobilize after $date_d days and $date_h hours."
    22 fi
    View Code

    利用case...esac的语句进行选择判断:

    结构:尾部分号为两个

     1 case  $变量名称 in   <==关键字为 case ,还有变量前有钱字号
     2   "第一个变量内容")   <==每个变量内容建议用双引号括起来,关键字则为小括号 )
     3     程序段
     4     ;;            <==每个类别结尾使用两个连续的分号来处理!
     5   "第二个变量内容")
     6     程序段
     7     ;;
     8   *)                  <==最后一个变量内容都会用 * 来代表所有其他值
     9     不包含第一个变量内容与第二个变量内容的其他程序运行段
    10     exit 1
    11     ;;
    View Code

    示例:

     1 case $1 in
     2   "hello")
     3     echo "Hello, how are you ?"
     4     ;;
     5   "")
     6     echo "You MUST input parameters, ex> {$0 someword}"
     7     ;;
     8   *)   # 其实就相当於万用字节,0~无穷多个任意字节之意!
     9     echo "Usage $0 {hello}"
    10     ;;
    11 esac
    View Code

    示例2:

     1 echo "This program will print your selection !"
     2 # read -p "Input your choice: " choice # 暂时取消,可以替换!
     3 # case $choice in                      # 暂时取消,可以替换!
     4 case $1 in                             # 现在使用,可以用上面两行替换!
     5   "one")
     6     echo "Your choice is ONE"
     7     ;;
     8   "two")
     9     echo "Your choice is TWO"
    10     ;;
    11   "three")
    12     echo "Your choice is THREE"
    13     ;;
    14   *)
    15     echo "Usage $0 {one|two|three}"
    16     ;;
    17 esac
    View Code

     函数设计与调用

     其内置变量和shell名称相似,$0 -- $n,为函数的局部变量

    示例:

     1 function printit(){
     2     echo -n "Your choice is "     # 加上 -n 可以不断行继续在同一行显示
     3 }
     4 
     5 echo "This program will print your selection !"
     6 case $1 in
     7   "one")
     8     printit; echo $1 | tr 'a-z' 'A-Z'  # 将参数做大小写转换!
     9     ;;
    10   "two")
    11     printit; echo $1 | tr 'a-z' 'A-Z'
    12     ;;
    13   "three")
    14     printit; echo $1 | tr 'a-z' 'A-Z'
    15     ;;
    16   *)
    17     echo "Usage $0 {one|two|three}"
    18     ;;
    19 esac
    View Code

    带函数参数的示例:

     1 function printit(){
     2     echo "Your choice is $1"   # 这个 $1 必须要参考底下命令的下达
     3 }
     4 
     5 echo "This program will print your selection !"
     6 case $1 in
     7   "one")
     8     printit 1  # 请注意, printit 命令后面还有接参数!
     9     ;;
    10   "two")
    11     printit 2
    12     ;;
    13   "three")
    14     printit 3
    15     ;;
    16   *)
    17     echo "Usage $0 {one|two|three}"
    18     ;;
    19 esac
    View Code

    循环:

    while []do done 循环  条件成立执行循环

    until []do done 循环  条件不成立执行循环

     示例1-n!!!!:真繁琐

    1 while [ "$yn" != "yes" -a "$yn" != "YES" ]
    2 do
    3     read -p "Please input yes/YES to stop this program: " yn
    4 done
    5 echo "OK! you input the correct answer."
    View Code
    1 until [ "$yn" == "yes" -o "$yn" == "YES" ]
    2 do
    3     read -p "Please input yes/YES to stop this program: " yn
    4 done
    5 echo "OK! you input the correct answer."
    View Code

    100内的累加:

    1 s=0  # 这是加总的数值变量
    2 i=0  # 这是累计的数值,亦即是 1, 2, 3....
    3 while [ "$i" != "100" ]
    4 do
    5     i=$(($i+1))   # 每次 i 都会添加 1 
    6     s=$(($s+$i))  # 每次都会加总一次!
    7 done
    8 echo "The result of '1+2+3+...+100' is ==> $s"
    View Code

    for var in xxx  do  done 循环,xxx内轮询一遍就结束。

     示例:

    1 for animal in dog cat elephant
    2 do
    3     echo "There are ${animal}s.... "
    4 done
    View Code

    显示用户,和对应的号:

    1 users=$(cut -d ':' -f1 /etc/passwd)  # 撷取帐号名称
    2 for username in $users               # 开始回圈进行!
    3 do
    4         id $username
    5         finger $username
    6 done
    View Code

    批量ping ip地址:使用seq 1 100取值,也可以使用{1..100}取值  和{a..g}类似

     1 network="192.168.1"              # 先定义一个网域的前面部分!
     2 for sitenu in $(seq 1 100)       # seq 为 sequence(连续) 的缩写之意
     3 do
     4     # 底下的程序在取得 ping 的回传值是正确的还是失败的!
     5         ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 || result=1
     6     # 开始显示结果是正确的启动 (UP) 还是错误的没有连通 (DOWN)
     7         if [ "$result" == 0 ]; then
     8                 echo "Server ${network}.${sitenu} is UP."
     9         else
    10                 echo "Server ${network}.${sitenu} is DOWN."
    11         fi
    12 done
    View Code

    获取目录下文件的权限:

     1 read -p "Please input a directory: " dir
     2 if [ "$dir" == "" -o ! -d "$dir" ]; then
     3     echo "The $dir is NOT exist in your system."
     4     exit 1
     5 fi
     6 
     7 # 2. 开始测试文件罗~
     8 filelist=$(ls $dir)        # 列出所有在该目录下的文件名称
     9 for filename in $filelist
    10 do
    11     perm=""
    12     test -r "$dir/$filename" && perm="$perm readable"
    13     test -w "$dir/$filename" && perm="$perm writable"
    14     test -x "$dir/$filename" && perm="$perm executable"
    15     echo "The file $dir/$filename's permission is $perm "
    16 done
    View Code

     for ((初始值;限制值;赋值运算)) do... done 循环:

    示例:1到x的累加:

    1 read -p "Please input a number, I will count for 1+2+...+your_input: " nu
    2 
    3 s=0
    4 for (( i=1; i<=$nu; i=i+1 ))
    5 do
    6     s=$(($s+$i))
    7 done
    8 echo "The result of '1+2+3+...+$nu' is ==> $s"
    View Code

    随机数和数组示例:

    a[1]="a"

    a[2]="b"

    a[3]="c"

    check=$(( ${RANDOM}*3/32767+1))

    echo "ans:${a[${check}]}"

     shell脚本跟踪与调试

    -n不执行脚本只查询语法,-v执行脚本前输出内容 -x使用到的脚本显示到屏幕上(跟踪)

     例如:sh -x file

  • 相关阅读:
    hdu 4614 线段树 二分
    cf 1066d 思维 二分
    lca 最大生成树 逆向思维 2018 徐州赛区网络预赛j
    rmq学习
    hdu 5692 dfs序 线段树
    dfs序介绍
    poj 3321 dfs序 树状数组 前向星
    cf 1060d 思维贪心
    【PAT甲级】1126 Eulerian Path (25分)
    【PAT甲级】1125 Chain the Ropes (25分)
  • 原文地址:https://www.cnblogs.com/bai2018/p/10737135.html
Copyright © 2011-2022 走看看