• 别人的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

  • 相关阅读:
    [leetcode] Best Time to Buy and Sell Stock II
    [leetcode] Best Time to Buy and Sell Stock
    [leetcode] Binary Tree Maximum Path Sum
    [leetcode] Triangle
    [leetcode] Populating Next Right Pointers in Each Node II
    [leetcode] Pascal's Triangle II
    [leetcode] Pascal's Triangle
    第三周周总结
    基础DP
    第二周周总结
  • 原文地址:https://www.cnblogs.com/bai2018/p/10737135.html
Copyright © 2020-2023  润新知