bash脚本编程

author author     2022-10-02     628

关键词:

bash脚本编程的结构:

bash脚本编程语言:

脚本类语言

解释性语言

过程式编程语言


过程式编程语言的结构:

顺序执行结构:默认

从上到下,自左而右执行所有的语句(命令)

选择执行结构:

当条件满足或不满足时才会执行对应的语句(命令)

循环执行结构:

重复执行某段语句(命令)


bash脚本编程语言中也具备上述结构:

顺序执行结构:默认

选择执行结构:

根据给定的条件逻辑判断结构或根据某个可选取的取值范围,进而选择某个分支结构中的命令语句予以执行的方式;


if:

选择执行结构的标准,根据条件的逻辑判断结果选择执行的语句内容;

case:

选择执行结构的标准,根据符合某特定范围取值标准来选择执行的语句内容;


循环执行结构:

对于特定语句内容,重复执行0次,1次或多次;

for:以遍历列表的方式来进行循环;

while:根据给定条件的逻辑判断结果进行循环;逻辑判断结果为真,才循环;否则,停止循环;

until:根据给定条件的逻辑判断结果进行循环;逻辑判断结果为假,才循环;否则,停止循环;

select:死循环,即没有默认退出条件的循环;利用循环提供一个可选择的列表;



bash脚本的执行结构值if选择执行结构:

if语句:

if 命令; then 命令; [ elif 命令; then 命令; ]... [ else 命令; ] fi


1.if语句的单分支结构:

if 命令; then 命令; fi


注意:是否会执行then后面的命令,取决于if后面的命令的执行状态返回值;

1.如果其返回值为真,则执行then后面的命令;

2.如果其返回值为假,则不执行then后面的命令;


建议在脚本中的书写格式:

if CONDITION ;then

STATEMENT

...

fi

或者

if CONDITION 

then

STATEMENT

...

fi


2.if语句的双分支结构:

if 命令; then 命令; [ else 命令; ] ;fi


注意:是否会执行then后面的命令,取决于if后面的命令的执行状态返回值;

1.如果其返回值为真,则执行then后面的命令;

2.如果其返回值为假,则不执行else后面的命令;


建议在脚本中的书写格式:

if CONDITION ;then

STATEMENT

...

else

STATEMENT

...

fi

或者

if CONDITION 

then

STATEMENT

...

else

STATEMENT

...

fi

3.if语句的多分支结构:

if 命令; then 命令; [ elif 命令; then 命令; ]... [ else 命令; ] fi


注意:是否会执行then后面的命令,取决于if后面的命令的执行状态返回值或elif和面的命令的执行状态返回值;

1.首先判断if后面的命令的状态返回值是否为真,如果为真就执行then后面的语句;如果为假,就继续判断第一个elif后面的命令                      的执行状态返回值;

2.第一个elif后面的命令的执行状态返回值为真,就执行第一个elif后面then后面的命令,否则,就继续判断第二个elif后面的命                      令的执行状态返回值;

3.以此类推,会判断每个elif后面的命令执行状态返回值是否为真;如果所有的if和elif后面的命令执行状态返回值均为假,则执                      行else后面的语句;



建议在脚本中的书写格式:

if CONDITION1 ;then

STATEMENT

...

elif CONDITION2 ; then

STATEMENT

...

elif CONDITION3 ; then

STATEMENT

...

...

else

STATEMENT

...

fi

或者

if CONDITION 

then

STATEMENT

...

elif CONDITION2

then

STATEMENT

...

elif CONDITION3

then

STATEMENT

...

...

else

STATEMENT

...

fi


注意:if的多分支结构,使用场景不多,而且有些时候,可以使用嵌套的单分支或双分支if结构代替if多分支结构;


嵌套的if结构:

if CONDITION1 ;then

if CONDITION2 ;then

if CONDITION3 ; then

STATEMENT

...

else

STATEMENT

fi

else

STATEMENT

...

fi

else

STATEMENT

...

fi


示例:

1.判断某个用户的默认登录shell是否为/bin/bash;

#!/bin/bash
#
USERNAME=$(cut -d : -f 1 /etc/shadow | sort -R | head -1)
USERSHELL=$(egrep "^$USERNAME>" /etc/passwds | cut -d : -f 7)
if [ "$USERSHELL" == "/bin/bash" ] ; then 
echo "${USERNAME}'s login shell is /bin/bash."
fi
unset USERNAME USERSHELL

2.判断某个用户的默认登录shell是否为/bin/bash;如果不是就显示它的登录shell;


#!/bin/bash
#
USERNAME=$(cut -d : -f 1 /etc/shadow | sort -R | head -1)
USERSHELL=$(egrep "^$USERNAME>" /etc/passwd | cut -d : -f 7)
if [ "$USERSHELL" == "/bin/bash" ] ; then 
echo "${USERNAME}'s login shell is /bin/bash."
else
echo "${USERNAME}'s login shell is ${USERSHELL}."
fi


bash脚本编程之用户交互使用:

位置参数变量:

$0:命令的本身,对于脚本而言,就是该脚本的路径;

$1,$2,...$N:脚本后面通过命令行给脚本传递的命令行参数;

N>9时,引用该位置变量时需要加{},即:${10}; $10,只会认为其是$1;


#!/bin/bash
#
#USERNAME=$(cut -d : -f 1 /etc/shadow | sort -R | head -1)
USERSHELL=$(egrep "^$1>" /etc/passwds | cut -d : -f 7)
if [ "$USERSHELL" == "/bin/bash" ] ; then 
echo "${1}'s login shell is /bin/bash."
fi


特殊变量:

[email protected]:给出的所有位置参数的列表,当使用双引号引用时,每个参数作为单独的字符串存在;

$*:给出的所有位置参数的列表,当使用双引号引用时,整个参数列表被当做一个字符串;

$#:表示除去$0之外,整个命令行中有多少个参数;



read命令:

Read a line from the standard input and split it into fields.

read [-ers] [-a 数组]  [-p 提示符] [-t 超时] [-u 文件描述符] [名称 ...]


-a array:定义索引数组;

-p promt:给用户输出提示信息;

-t timeout:用户输入的超时时间;

name:变量或数组的名称;如果省略此内容,bash会将read读到的信息直接保存到内置的名为REPLY

变量中;



注意:

Linux哲学思想之一:尽量不与用户交互;


在使用read命令时,通常会使用-t选项来指定与用户交互的时间,一旦时间超过预定时间,脚本中后续的命令内容会自动被执行;因此,通常需要在后面判断通过read赋值的变量值是否为空,如果为空,我们可能需要为该变量提供默认值;

read -t 5 VAR1

[ -z $VAR1  ] && VAR1=value1




管理用户脚本:

脚本可以接受两个参数,第一个参数为-a或-d,第二个参数为用户名;若果第一个参数时-a,则创建其后面参数命令的用户;如果第一个参数为-d,则删除其后面参数命令的用户;


#!/bin/bash
#
if [ $# -ne 2 ] ; then
  echo "Make sure provide TWO arguments."
  exit 5
fi
if [ $1 == '-a' ] ; then
  if ! id $2 &> /dev/null ; then
    useradd $2 &> /dev/null
    echo $2 | passwd --stdin $2 &> /dev/null
    echo "User $2 created succesfully and password changed to it's username."
  else
    echo "$2 exists already."
  fi
elif [ $1 == '-d' ] ; then
  if id $2 &> /dev/null ; then
    userdel -r $2 &> /dev/null
    echo "User $2 delete finished."
  else
    echo "$2 does not exist yet."
  fi
else
  echo "Usage: $(basename $0) -a USERNAME | -d USERNAME"
  exit 6
fi



改进版:


#!/bin/bash
#
if [ $# -ne 1 ] ; then
  echo "Make sure provide ONE argument."
  exit 5
fi
if [ $1 == '-a' ] ; then
  read -p "Please input a username for creating: " USERNAME
  if ! id $USERNAME &> /dev/null ; then
    useradd $USERNAME &> /dev/null
    echo $USERNAME | passwd --stdin $USERNAME &> /dev/null
    echo "User $USERNAME created succesfully and password changed to it's username."
  else
    echo "$USERNAME exists already."
  fi
elif [ $1 == '-d' ] ; then
  read -p "Please input a username for deleting: " USERNAME
  read -t 5 -p "confirm? Input 'yes' to continue: " CHOICE
  [ -z $CHOICE ] && CHOICE='no'
  if [ $CHOICE == 'yes' ] ; then
    if id $USERNAME &> /dev/null ; then
      userdel -r $USERNAME &> /dev/null
      echo "User $USERNAME delete finished."
    else
      echo "$USERNAME does not exist yet."
    fi
  else
    echo
    echo "$USERNAME is not deleted."
  fi
else
  echo "Usage: $(basename $0) { -a | -d }"
  exit 6
fi


判断用户通过命令行给的一个参数是否为整数。


#!/bin/bash
#
if [ $# -ne 1 ] ; then
 echo "确定这是一个参数。"
 exit 4
fi
if !  [[ $1 =~ [^[:digit:]] ]] &> /dev/null ; then
  echo "这是一个整数。"
else
  echo "这不是一个整数。"
fi



循环执行结构:

循环:将某一段代码或者命令重复执行0次,1次或多次;


一个好的循环结构,必须要包括两个重要的环节;

1.进入循环的条件:

  在符合要求或满足条件时才开始循环;



  2.退出循环的条件:

  达到某个要求或符号某个条件时需要结束或终止循环的执行;



for循环:

1.遍历列表的循环:

Execute commands for each member in a list.

格式:

for NAME [in WORDS ... ] ; do COMMANDS; done



建议在脚本中的书写格式:

for VAR_NAME in LiST ; do

循环体

done

或者

for VAR_NAME in LiST 

do

循环体

done


注意:

VAR_NAME :任意指定的变量名称,变量的值是从LIST中遍历获取的各个元素;

LIST:for循环需要遍历的列表;可以通过以下方式生成列表;

1.直接给出列表;

2.纯整数列表;

  1)花括号展开:

{FIRSTNUM..LASTNUM}

{FIRST,SECIND,THIRD,...LAST}

  2)seq命令:

  seq [OPTION]... LAST

       seq [OPTION]... FIRST LAST

       seq [OPTION]... FIRST INCREMENT LAST


   3.花括号展开:

    {FIRST..LAST} (字符)

   4.命令的执行结果:

    ls /etc

    grep /PATH/TO/SOMEFILE

   5.GLOBBING

   6.某些特殊变量的值:

    $*,&@

循环体:

一般来说,循环体中应该能够用到VAR_NAME变量的值的命令或命令的组合;如果循环体中的命令并没有用到VAR_NAME变量的值得话,列表的元素个数就是此次for循环的次数;



使用for循环,计算1到100的数字之和:

#!/bin/bash
#
for I in {1..100} 或者 $(seq 1 100}; do
SUM=$[SUM+I]
或者
let SUM+=$I
done
echo "The summary is: $SUM:"


1到100所有奇数的和

#!/bin/bash
#
for I in {1..100..2} 或者${seq 1 2 100}; do
SUM=$[SUM+I]
或者
let SUM+=$I
done
echo "The summary is: $SUM:"


0到100所有偶数的和

#!/bin/bash
#
for I in {0..100..2} 或者${seq 0 2 100}; do
SUM=$[SUM+I]
或者
let SUM+=$I
done
echo "The summary is: $SUM:"



写一个脚本,能够通过-a或-d选项添加或删除一个或多个用户账户;



#!/bin/bash
#
if [ $# -lt 2 ] ; then
  echo "Make sure provide more than TWO arguments."
  exit 5
fi
if [ $1 == '-a' ] ; then
  shift
  for I in "[email protected]" ; do
    if ! id $I &> /dev/null ; then
      useradd $I &> /dev/null
      echo $I | passwd --stdin $I &> /dev/null
      echo "User $I created succesfully and password changed to it's username."
    else
      echo "$I exists already."
    fi
  done
elif [ $1 == '-d' ] ; then
  shift
  for J in "[email protected]" ; do
    if id $J &> /dev/null ; then
      userdel -r $J &> /dev/null
      echo "User $J delete finished."
    else
      echo "$J does not exist yet."
    fi
  done
else
  echo "Usage: $(basename $0) -a UNAME1 [UNAME2 ...] | -d UNAME1 [UNAME2 ...]"
  exit 6
fi



总结:

1.进入循环的条件:LIST中尚有未被取尽的元素;

2.退出循环的条件:LIST中的元素被取尽;

3.for循环几乎不会出现死循环;

4.在执行循环的过程中,需要将整个LIST载入内存,因此,对于大列表来说,可能会消耗较多的内存及CPU资源;



指定指定范围内自然数的和:


#!/bin/bash
#
declare -i SUM=0
read -p "Please input TWO integer: " INT1 INT2
if [[ $INT1 =~ [^[:digit:]] ]] ; then
  echo "$INT1 must be an integer."
  exit 5
fi
if [[ $INT2 =~ [^[:digit:]] ]] ; then
  echo "$INT2 must be an integer."
  exit 5
fi
if [ $INT1 -gt $INT2 ] ; then
  for I in $(seq $INT2 $INT1) ; do
# SUM=$[SUM+I]
    let SUM+=$I
  done
  echo "The summary is: $SUM"
else
  for I in $(seq $INT1 $INT2) ; do
# SUM=$[SUM+I]
    let SUM+=$I
  done
  echo "The summary is: $SUM"
fi



打印有"*"组成的倒置的等腰三角形;

********* 1行,0个空白字符,9个"*"

*******  2行,1个空白字符,7个"*"

 *****   3行,2个空白字符,5个"*"

  ***  4行,3个空白字符,3个"*"

   *  5行,4个空白字符,1个"*"


     N行,N-1个空白字符,2*(总行数-当前行数)+1个"*"


#!/bin/bash
#
LINENUM=$1
for I in $(seq $LINENUM) ; do
for J in $(seq $[I-1]) ; do
echo -n " "
done
for K in $(seq $[2*(LINENUM-I)+1]) ; do
echo -n "*"
done
echo
done




打印九九乘法表:

第一行:1个

第二行:2个

...

第九行:9个


#!/bin/bash
#
for I in {1..9} ; do
for J in $(seq $I) ; do
echo -ne "$I×$J=$[I*J]	"
done
echo
done


#!/bin/bash
#
for (( I=1 ; I<=9 ; I++ )) ; do
  for (( J=1 ; J<=I ; J++ )) ; do
    echo -ne "$J×$I=$[I*J]	"
  done
  echo
done


以上两个例子,均使用for循环的嵌套;往往需要两层的循环嵌套才能打印平面效果;外层的for循环,负责控制行数输出;内层的for循环,负责每一行中各个      列的输出;





2.通过控制变量实现for循环;

for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done

可以在脚本中携程如下格式:

for ((: for (( exp1; exp2; exp3 )) ; do

COMMANDS

done


exp1:表达式1,为指定的变量赋初始值;

exp2:表达式2,此次循环的退出条件;

exp3:表达式3,指定的变量值得变化规律;


计算从1到100的自然数的和:

#!/bin/bash
#
for(( i=1 ; I<=100 ; I++ )) ; do
let SUM+=$I
done
echo "The summary is :$SUM"


通过 bash 脚本将 bash 脚本添加到 crontab

】通过bash脚本将bash脚本添加到crontab【英文标题】:addbashscripttocrontabviabashscript【发布时间】:2022-01-2010:48:20【问题描述】:我想将带有文件名的日期添加到我的bash脚本中,该脚本将通过脚本添加到crontab文件中。问题是crontab文... 查看详情

bash脚本编程

bash脚本编程的结构: bash脚本编程语言: 脚本类语言 解释性语言 过程式编程语言 过程式编程语言的结构: 顺序执行结构:默认 从上到下,自左而右执行所有的语句(命令) 选择执行结构: 当条件满足或不满足时才会执... 查看详情

bash变成

一、Bash脚本编程风格二、Bash条件测试:三、脚本的状态返回值       四、练习脚本:五、if 语句一、Bash脚本编程风格   脚本格式:   #!/bin/bash   #description:sayhello&nb 查看详情

如何在路径有空格的另一个 bash 脚本中运行 bash 脚本?

】如何在路径有空格的另一个bash脚本中运行bash脚本?【英文标题】:Howtorunbashscriptinsideanotherbashscriptwherepathhasspaces?【发布时间】:2021-08-2800:49:44【问题描述】:您好,我正在尝试从另一个bash脚本中调用一个bash脚本。结构如下... 查看详情

bash变量及bash脚本编程算术运算介绍

1、常用命令bash特性命令介绍:hash命令作用:缓存此前命令的查找结果,缓存外部命令,不能缓存内嵌命令;加快程序运行用法:他是一个内嵌命令[[email protected]~]#hash     //查看此前运行过的命令的查找结... 查看详情

bash脚本

{**Bash脚本基础**}BASH=GNUBourne-AgainShell,BASH是GNU组织开发和推广的一个项目。Bash脚本类似批处理,简单来讲就是把许多的指令集合在一起,并提供循环、条件、判断等重要功能,语法简单实用,用以编写程序,大大简化管理员的操... 查看详情

bash脚本

{**Bash脚本基础**}BASH=GNUBourne-AgainShell,BASH是GNU组织开发和推广的一个项目。Bash脚本类似批处理,简单来讲就是把许多的指令集合在一起,并提供循环、条件、判断等重要功能,语法简单实用,用以编写程序,大大简化管理员的操... 查看详情

bash脚本编程学习笔记

  bash脚本语言,不同于C/C++是一种解释性语言。即在执行前不需要事先转变为可执行的二进制代码,而是每次执行时经解释器解释后执行。bash脚本语言是命令的堆砌,即按照实际需要,结合命令流程机制实现的源程序,因此... 查看详情

bash脚本编程基础

脚本文件格式第一行顶格写脚本的解释器路径,例如bash脚本需要写:#!/bin/bash第二行写描述:#description:sayhello第三行写版本:#version:1.0.0第四行写作者:#author:Jerry<[email protected]>第五行写日期:#date:2017-10-23要写代码注释... 查看详情

如何使用 bash -c 调用 bash 脚本函数 [重复]

】如何使用bash-c调用bash脚本函数[重复]【英文标题】:Howtocallabashscriptfunctionusingbash-c[duplicate]【发布时间】:2021-06-0407:20:55【问题描述】:[更新]请注意,为了满足minimalreproducibleexample,这是本文的简化代码。脚本中会有更多的功... 查看详情

实验楼-高级bash脚本编程指南

实验1.Bash介绍与入门1.简介:Bash是一个为GNU计划编写的Unixshell,它是许多Linux平台默认使用的shell    shell是一个命令解释器,是介于操作系统内核与用户之间的一个绝缘层。所有的UNIX命令和工具再加上公共程序,对于Shell脚... 查看详情

bash脚本编程之条件判断

1、bash脚本编程格式:顶格写#!/bin/bash接下来给出一些注释信息,以#开头如:    #description    #version    #auhorceshi<[email protected]>   &nbs 查看详情

bash颜色变量数组相关脚本示例

...理方式、数组变量、shell的过程式编程语言以及部分简单脚本例子。一、bash的颜色显示规则(颜色代码)bash的颜色代码,是ASCII编码对于颜色进行设置。颜色代码中,字符串 查看详情

bash脚本编程之用户交互

bash脚本编程之用户交互:read[option]...[name...]    -p‘PROMPT‘  读取输入的内容    -tTIMEOUT    超时时间,如果超过了该时间,继续执行下面代码bash-n/path/to/some_script&nbs 查看详情

用于运行 php 脚本的 Bash 脚本

】用于运行php脚本的Bash脚本【英文标题】:Bashscripttorunphpscript【发布时间】:2011-07-2706:54:24【问题描述】:我有一个php脚本,我想使用bash脚本运行,所以我可以使用Cron每隔一分钟左右运行一次php脚本。据我所知,我需要创建bas... 查看详情

bash特性中多命令执行的逻辑关系和bash脚本编程之编程

bash的特性之多命令执行的逻辑关系: 1.命令替换  COMMAND1 $(COMMAND2)  (先执行COMMAND2,把COMMAND2的执行结果传递给COMMAND1来执行) 2.管道  COMMAND1|COMMAND2|COMMAND3 ...  (先执行COMMA 查看详情

bash 脚本不能通过 crontab 工作

】bash脚本不能通过crontab工作【英文标题】:bashscriptdoesn\'tworkthroughcrontab【发布时间】:2017-10-2701:59:17【问题描述】:我正在运行一个将文件传输到我的AWS存储桶的bash脚本。如果我通过终端运行bash脚本,它可以正常工作(通过./... 查看详情

bash编程

一、bash判断字符类型二、bash脚本编程语法三、shell的99乘法表一、bash判断字符类型 //输入一个字符串,判断其类型方法一、printf实现Printf实现方法格式替换符:   %b相对应的参数被视为含有要被处理的转义序列之... 查看详情