夜勿眠 发表于 2018-8-20 14:12:28

20150913 Linux Shell-linux学习点滴

  Part 1 学习整理
  第一、shell概述
  Bshell是解释器
  硬件—》Kernel--->库----》程序员调用库进行程序开发
  守护进程,服务进程(后台运行、非交互):启动?开机时自动启动;
  交互式进程:shell应用程序
  广义接口:GUI,CLI
  GUI
  CLI:
  promt
  COMMAND
  词法分析: 命令,选项,参数
  内建命令:shell自带
  外部命令:PATH环境变量所定义
  fork() 创建为一个进程;系统调用的一种实现
  把要运行的一系列命令,写在文件中;解释器读取文件,逐条运行。
  脚本或程序源文件:文本文件,由文本文件由机器执行的方式
  两种方式:
  编译执行:预处理-->编译-->汇编-->链接;事先完成,结果:二进制程序文件
  C, C++
  解释执行:由解释器全程参与运行过程,无需要事前转换。每次读取一行,运行一行;
  Python:编程库
  程序控制结构,调用编程库完成程序编写;
  库文件:功能模块,在编程中可调用;通过其API;
  Bash:编程(交互式接口,提供编程的能力)
  程序控制结构,调用机器上命令程序文件进行程序编写;例如ls、Cat等
  这些命令可脱离shell执行。相关程序文件不依赖程序库
  外部命令:各GNU应用程序提供
  第二、程序编程方式
  程序:指令+数据
  算法+数据结构
  过程式编程:以指令为中心,设计算法,数据服务于算法;
  对象式编程:以数据为中心,设计数据结构(类),程序服务于数据结构;应用大于
  bash过程式编程:
  顺序执行:逐个执行
  选择执行:只执行其中一个分支
  循环执行:一段代码要执行0,1或多遍
  编程元素:变量、流程、函数
  第三:shell变量的定义
  A:变量作用范围
  变量:可变化的量,命名内存空间
  一个脚本一个进程运行,一个进程内部多个函数,每个函数
  内部可使用局部变量,作用范围某函数执行过程。
  bash环境:作用范围
  本地变量:当前shell进程;
  环境变量:当前shell进程及其子进程;
  局部变量:某个函数执行过程;
  位置参数变量:在脚本中引用传递给脚本的参数;在函数中引用传递给函数的参数;
  特殊变量(内建某些特殊值):$?, $*, $@, $#, $$
  B:变量值类型
  数值,字符;
  数值:(每种类型有单独的内存存储空间)
  整数
  浮点数
  字符:
  ASCII码(7位2进制数)
  数值与字符的区别:
  字符:1, 2, 0(每个字符8个2进制数)
  数值:120 --> 转换成2进制数(7位2进制)
  变量类型的作用:
  存储空间
  运算
  存储格式
  语言对变量类型的支持力度:
  强类型:C++(类型严格区分)
  弱类型:变量类型不严格区分;
  默认存储机制:bash为字符,也可指定为数值型
  C:bash变量的定义使用
  bash的变量使用特点:弱类型、无须事先声明;
  1)本地变量:只在本进程有效,在父进程无效
  示例:运行二个bash,第一个为父进程、第二个为子进程
  父进程定义变量$animal,echo $animal输出为pig,而在
  子进程运行输出echo $animal为空

  name=value   如果为字符串需引号(单引号或双引号皆可)括起来,如无空格可直接使用
  name: 变量名
  =:赋值符号
  value:值
  变量名:只能包含数字、字母和下划线;且不能以数字开头;(不要使用大写开头)
  引用变量:${name}, $name,返回值用echo ${name}
  引用(共4种,常用三种如下):
  弱引用: "", 其内部的变量引用会被替换为变量值;(变量替换会发生)
  强引用:'',其变量的变量引用会保持原有字符;
  命令引用:`COMMAND`, $(COMMAND),引用命令的执行结果;反引号` `
  声明为整型:
  declare -i name[=value]
  let name=value
  查看所有变量:set
  生命周期:
  创建:开始
  销毁:(销毁法则)
  自动销毁:shell进程终止;
  手动销毁:unset name(变量名)
  2)环境变量:
  作用范围当前进程及子进程
  被“导出”的本地变量
  export name[=value]
  declare -x name[=value]
  示例:name=’obama’ #这里为本地变量
  exprot name   #导出后为环境变量

  分别进入三个bash子进程,使用echo $name
  正常可以输出相关值obama

  查看所有环境变量:env, printenv, export

  销毁:(手动、自动)
  unset name
  第四、脚本:文本文件
  运行脚本:事实上是运行一个bash进程,此进程负责从脚本文件中读取一个执行逻辑,
  而后由bash进程负责解析并运行此逻辑;脚本作为参数提供bash运行。
  1)启动脚本:
  两种方式:
  (1) # bash /PATH/TO/SCRIPT_FILE   bash加路径
  (2) 一个执行权限, (单独运行)   # ./PATH/TO/SCRIPT_FILE
  语法格式:
  shebang语法:第一行顶格写)
  #!/bin/bash   (解释器路径,运行下而脚本中内容)
  第一行:顶格给出shebang
  注释行:#
  脚本示例:执行或者./shell名称(之前增加执行权限)

  *备注:--stdin表示可以用任意文件做标准输入,这里是echo
  其中第一个testuser1是为密码,后利用—stdin进行引用
  2)bash的常用选项:
  -n: 检查脚本中的语法错误;
  -x:调试执行脚本;
  bash脚本名称:直接运行

  3)命令状态结果:
  bash进程用于追踪执行的命令成功与否的状态:
  0: 成功
  1-255:失败(其中1、2、127、63、64是bash内置其它可自定义)
  特殊变量:
  $?:上一条命令的执行状态结果;

  布尔型:
  “真”:成功
  “假”:失败
  自定义脚本的状态结果:
  exit
  注意:脚本中任何位置执行了exit命令即会终止当前shell进程;

  4)条件测试:   
  界定程序执行环境;
  (1) 根据运行的命令的状态结果; 根据结果$?返回值进行判断!结果成功或失败
  (2) 测试表达式
  test EXPRESSION    例如:
  [ EXPRESSION ]   注意:[ ]内部前后二端有空格,无空格会提示语法内建命令
  ` EXPRESSION `    同样需要空格,bshell关键字
  测试表达式常规包括以下三种:
  第一种:整数测试:双模操作符,隐含着做数值大小比较,所以不要给变量引用加引用;
  $A -gt $B:是否大于;是则为“真”,否则为“假”;   A变量中的数值是否大于B变量的值

  返回非0说明是假的
  $A -ge $B: 是否大于等于;
  $A -lt $B:是否小于; (less then)
  $A -le $B: 是否小于等于;
  $A -eq $B: 是否等于; (equal)
  $A -ne $B:是否不等于;
  第二种:字符串测试:ASCII码比较数值越大,字符比较时其值越大;
  有变量双引号、无变量单引号,同时采用双引号
  "$A" > "$B":是否大于;
  "$A" < "$B":是否小于;
  "$A" == "$B":是否等于; 比较常用

  "$A" != "$B":是否不等于;
  -z "$A":是否为空;空则为“真”,否则为“假”
  -n "$A":是否不空;不空则“真”,空则为“假”
  注意:应该使用双中括号` EXPRESSION `
  第三种:文件测试:测试文件的存在性以及属性;单目操作符
  -e $file: 是否存在;存在则为“真”,否则为“假”; 后面$file为文件路径
  -a $file: 同上;
  -f $file:文件是否存在且为普通文件;
  -d $file:文件是否存在且为目录;
  -h $file:是否存在且为符号链接文件;
  -L $file: 同上
  -b $file:是否存在且为块设备文件;
  -c $file:是否存在且为字符设备文件;
  -S $file:是否存在且为套接字文件;
  -p $file: 是否存在且为管道文件;
  第四种:权限测试
  -r $file: 当前用户对文件是否拥有读权限;
  -w $file:当前用户对文件是否拥有写权限;
  -x $file:当前用户对文件是否拥有执行权限;
  -u $file:文件是否拥有SUID权限;
  -g $file:文件是否拥有SGID权限;
  -k $file:文件是否拥有sticky权限;
  -O $file: 当前用户是否为指定文件的属主;
  -G $file: 当前用户是否为指定文件的属组;
  示例:

  第五种:双目操作符: (二个操作符)
  $file1 -nt $file2: file1是否新于file2, file1的最近一次的修改时间戳是否晚于file2的; (new then)
  $file1 -ot $file2: file1是否旧于file2, file1的最近一次的修改时间戳是否早于file2的; (old then)
  $file1 -ef $file2:file1与file2是否指向了同一个inode;测试二者是否为同一个文件的硬链接;
  第六种:特殊设备:
  /dev/null: 空,bit buckets,吞下所有数据,并直接丢弃; ,作为输出设备使用
  示例    &>/dev/null
  /dev/zero:吐出一堆0;作为输入设备作用
  5) bash之条件判断(选择执行):
  包括顺序、选择、if/then, case ,fi结尾
  单分支:
  if CONDITION; then
  if-true-分支
  fi
  多分支:
  if CONDITION; then
  if-true-分支
  else
  if-false-分支
  fi
  取反
  ! CONDITION: 取反


  上述示例中如果条件为假,则不运行后续”echo $username|….”命令
  练习:写一个脚本
  如果某路径不存在,则将其创建为目录;否则显示其存在,并显示内容类型;
      #!/bin/bash  
      #
  
      filename="/tmp/x/y/z/testdir"
  
         if [ -e $filename ]; then
  
             echo "$filename exists."
  
             file $filename
  
      else
  
         mkdir -p $filename   #-P表示父目录同时创建
  
         fi
  6)脚本参数(位置参数变量):
  # ./script.sh /etc/fstab /etc/grub2.cfg (centos 7)
  $0          $1          $2
  位置参数变量:$1, $2, ...
  ${10}二位数字即超过10时中{}
  示例:判断输入的文件是否存在?如果存在则计算行数
  如果不存在则输出不是文件

  运行利用shell名称filename形式./file2.sh /etc/fstab
  ./file2.sh为脚本,/etc/fstab为变量$1的值

  特殊变量:判断参数是输入
  $?: 命令的状态结果;
  $0:表示脚本名称
  $#: 传递给脚本或函数的参数的个数;
  $*和$@: 引用传递给脚本或函数的参数列表;
  示例:$#用于判断./shell.sh文件后面是否输入参数
  当空时输出Usage:./shell.sh ./shell.sh后面要有参数文件路径。
  exit 1条件不满足出退出当前shell脚本
  当有路径参数时正常输出。

  shift :轮替
  例如有三个参数   1,2,3,当启用该参数时,第一次用完后将参数1
  替出,这时参数为2,3,原用参数前移一位。以此类推。
  示例如下:

  $*表示所有引用参数
  每次引用$1后,shift后后续变量前移。分别以A,B,C输出,
  $*输出最后一个C。shift 2 表示一次踢2个例如,一般用于
  循环环境中。

  与用户交互:
  read命令: read从输入中读取保存到指定变量当中
  help read查看命令
  read VAR...
  -p "PROMPT"    提示符
  -t timeout   超时时间

  上面将文件路径分别保存到变量file1、 file2中
  在交互输入中包括二种状态
  第一种情况:交互输入的值在于变量
  当给定的变量与输入不匹配时,自左至右分别赋值,
  把剩余给最后一个变量 。示例如下:,将debug message给变量b

  第二种情况 :变量值大于交换输入的值,后续的变量将不会赋值。
  输出则为空。示例:变量a ,b 赋值,c为空

  在交互前输入相关提示信息,read可利用-p选项
  echo –n输入不换行


  示例:
       #!/bin/bash         #  
            read -p "Plz enter a username: " -t 5 username
  
            if [ -z "$username" ]; then   #变量值为空值则赋默认值为myuser                     username="myuser"               fi
  
            if id $username &> /dev/null; then   #如果用户存在则输出                  echo "$username exists."               else                     useradd $username               fi
  7) 命令引用: 引用命令的执行结果
  `COMMAND`, $(COMMAND)
  引用命令的执行结果;
  (1) ls `which cat`   which cat的结果作为ls的参数使用
  (2) lines=$(wc -l /etc/fstab | cut -d' ' -f1)   变量赋值

  将结果15赋给变量lines
示例:  
            #!/bin/bash
  
            #
  
            if [ -f $1 ]; then
  
             lines=$(wc -l $1 | cut -d' ' -f1)                                       echo "$1 has $lines lines."
  
             else
  
            echo "$1 not exists or not a file."                                       fi
  练习:写一个脚本,完成如下功能;
  判断给定的两个数值,孰大孰小;
  给定数值的方法:脚本参数,命令交互;
#!/bin/bash  
#
  
read -p "Plz enter two integer: " -t 10 num1 num2
  
    if [ -z "$num1" ]; then
  
      echo "Plz give two integers."
  
       exit 1
  
    fi
  

  
    if [ -z "$num2" ]; then
  
      echo "Plz give tow integers."
  
      exit 1
  
   fi
  
   if [ $num1 -ge $num2 ]; then
  
   echo "Max: $num1, Min: $num2."
  
   else
  
   echo "Max: $num2, Min: $num1."
  
   fi
  8)循环语句:
  内置三种循环语句:for, while, until
  第一:定义
  循环:将循环体代码执行0、1或多次;
  进入条件:进入循环的条件;
  退出条件:循环终止的条件;
  第二:语法定义
  A)语法结构
  for VARIABLE in LIST; do
  循环体
  done(到此结束)
  LIST:是由一个或多个空格或换行符分隔开的字符串组成;
  把列表的每个字符串逐个赋值给VARIABLE表示的变量;
  示例:
  for username in user1 user2 user3; do
  循环体
  done
  user1给username赋值
  进入条件:列表非空; (将user1、至user3为进行条件)
  退出条件:列表遍历结束;(到最后一个变量)
  示例:
            添加10个用户,user1-user10;  
                #!/bin/bash
  
                #
  
                for username in user1 user2 user3 user4 user5; do                         if id $username &> /dev/null; then                                  echo "$username exists."                                           else
  
                  useradd $username                                             echo "Add user $username finished."                               fi
  
                done
  B)LIST的生成方法
  Part 1:(1) 整数列表
  (a) {start..end}
  (b) $(seq [start `step` end)    整数步进方式(seq是内部命令)默认从1开始
  例如:seq 10 ,自动生成1-10,或者seq 10 20自动生成10-20
  seq 1 2 10 表示从1开始,到10结束,步进为2,这样输出为1,3,5,7,9奇数
  seq 2 210 表示输出2,4,6,8,10 偶数
  (2) 直接给出列表
  (3) glob   (文件名、通配方式)
  (4) 命令生成(命令输出为列表,以空格或换行符组成的都为列表)
  示例1:数值列表
  #!/bin/bash
  #
      for i in {1..10}; do  
            if id user$i &> /dev/null; then
  
                  echo "user$i exists."
  
            else
  
                  useradd user$i
  
            echo "Add user user$i finished."
  
             fi
  
       done
  示例2:glob
  file判断文件类型,判断/var/log目录下的所有文件类型
#!/bin/bash  
#
  
         for filename in /var/log/*; do
  
               file $filename
  
         done
  示例:命令生成列表3 ,判断用户基本组的组名,
  其中$(cut -d: -f1 /etc/passwd)为命令引用
#!/bin/bash  
#
  
for username in $(cut -d: -f1 /etc/passwd); do
  
echo "$username primary group: $(id -n -g $username)."
  

  
   #备注:$(id -n -g $username)表示命令结果放到此处
  
done
  Part 2 算术运算
  let命令
  算术运算符       +, -, *, /, %, **
  (1) $[$A+$B]   求和 $[]
  (2) $(($A+$B))   $((   ))   与$ [ ] 结果相同
  (3) let VARIABLE=$A+$B   let命令需要赋值后引用,方式(1)(2)不需要赋值
  示例:a=3b=4 (赋值)
  let sum=$a + $b
  echo $sum

  (4) VARIABLE=$(expr $A + $B)       expr命令引用,引用后给变量

  expr 后面需要空格
  示例:求100以内所以正整数之和;
#!/bin/bash  
#
  
   declare -i sum=0   申明变量,给初始值
  
for i in {1..100}; do
  
   sum=$[$sum+$i]
  
    done
  
echo $sum
  练习:求100以内所有偶数之和;
  使用至少三种方法实现;
#!/bin/bash  
#
  
   declare -i sum=0
  
    for i in $(seq 0 2 100); do
  
      sum=$(($sum+$i))
  
    done
  
   echo "Even sum: $sum."
#!/bin/bash  
#
  
declare -i sum=0
  
   for i in {1..100}; do
  
      if [ $[$i%2] -eq 0 ]; then
  
         sum=$[$sum+$i]
  
      fi
  
   done
  
echo "Even sum: $sum."
  Part3 增强型赋值:
  +=      自身赋值
  sum=$[$sum+$i]
  let sum+=$i(help let)
  -=, *=, /=, %=   (除、取模)
  let count=$[$count+1]   --> let count+=1 --> let count++    自动+1
  let count=$[$count-1] --> let count-=1 --> let count--   自动减1
  示例:显示/etc目录下所有普通文件列表,而后统计一共有多少个文件;
#!/bin/bash  
#
  
declare -i count=0
  
   for file in /etc/*; do
  
       if [ -f $file ]; then
  
         let count++
  
         echo "$count $file"
  
       fi
  
      done
  
          echo "Total: $count files."
  Part 4 测试表达式:
  整数测试:-gt大于, –lt 小于, -ge, -le, -eq, -ne
  字符串测试:==, >,/dev/null; then                        echo "$username is logged."
  
   break
  
   else
  
   let count++
  
   echo "$count $username is not login."
  
   fi
  
   sleep 3
  
   done
#!/bin/bash  
#
  
declare -i count=0
  
username=$1
  
if [ $# -lt 1 ]; then   #判断参数是否为空
  
    echo "At lease one argument."
  
      exit 1
  
fi
  
if ! id $username &> /dev/null; then
  
    echo "No such user."
  
    exit 2
  
fi
  until who | grep "^$username" &> /dev/null; do (条件作为循环条件)
  let count++
  echo "$count $username is not login."
  sleep 3
  done
  echo "$username is logged on."
  while循环的特殊用法:
  遍历文件的每一行:
  while read VARIABLE; do
  循环体
  done < /PATH/FROM/SOME_FILE   #后为重定向,提供给
  VARIBLE
  示例:找出UID为偶数的所有用户,显示其用户名和ID号;
#!/bin/bash  
#
  
while read line; do
  
   userid=$(echo $line | cut -d: -f3)
  
      if [ $[$userid%2] -eq 0 ]; then                                 echo $line | cut -d: -f1,3
  
      fi
  
done < /etc/passwd#将/etc/passwd传给 line变量,从第一行开始操作)
  for循环的特殊用法:
  for ((expr1;expr2;expr3)); do
  循环体
  done
  expr1: 定义控制变量,并初始赋值;
  expr2: 循环控制条件;
  进入条件:控制条件为“真”
  退出条件:控制条件为“假”
  expr3: 修正控制变量
            示例:求100以内所有正整数之和;                   #!/bin/bash  
#
  
declare -i sum=0
  
for ((i=1;i /dev/null; then   #判断用户是否存在                  return 2
  
fi
  
userid=$(id -u $1)   #取出ID
  
   if [ $[$userid%2] -eq 0 ]; then   #判断userid的奇偶性                   echo "$1, Even user ID."
  
   else
  
       echo "$1, Odd user ID."
  
   fi               }
  以上函数定义完成
  evenid root
  evenid
  echo $?#echo作为输出数据
  evenid rooooooooooooot
  echo $?
  #以上都在同一个脚本当中
  第六:模块化编程
  功能:把脚本文件中的代码分隔为多段,放在不同的文件中
  假设/root/bin/srv目录有两个文件:
  (1) 函数文件如示例start,restart、
  (2) 脚本文件
  为脚本使用配置文件
  一个文件中只定义变量
  脚本文件source此变量定义的文件
  变量的作用域:
  局部变量:
  local VARIABLE=value
  示例:

  输出为

  存活时间:
  函数执行开始,至函数返回结束;
  示例:
  functins定义文件
  包括Start,stop,restart,status,*等文件定义
  start() {   #定义start函数
  if [ -f $lockfile ]; then
  echo "$prog is started yet."
  else
  touch $lockfile && echo "Starting $prog ok..." || echo "Starting $prog failed..."
  fi
  }
  如下中. 脚本文件source此变量定义

  运行hisrv.sh文件,要求在一个目录下运行:调用./hisrv.sh start

  示例2:
  在一个同一目录创建username.conf文件内容如下:本文件中只定义变量

  在脚本中source此定义的文件,只需要修改username.conf文件变量
  脚本useradd.sh
  如果文件可读,利用.    source username.conf

  作业:上述关于bash编辑所有语法知识点和总结,要求图文并茂
  Part 2:作业部分
  作业5:写一个脚本:如果某路径不存在,则将其创建为目录;
  否则显示其存在,并显示内容类型

  作业6:
  写一个脚本,完成如下功能;判断给定的两个数值,孰大孰小;给定数值的方法:
  脚本参数,命令交互;(使用read,依然如此简单)

  作业7:求100以内所有奇数之和
  方法1: while循环

  方法2:until

  方法3:

  作业8:
  写一个脚本实现如下功能:
  (1) 传递两个文本文件路径给脚本;
  (2) 显示两个文件中空白行数较多的文件及其空白行的个数;
  (3) 显示两个文件中总行数较多的文件及其总行数;
  首先定义二个文件,分别为file1,file2,路径为/tmp/51cto/mkshell/
  脚本如下:用read –P 读取文件路径,四个条件分别赋值进行比较

  作业9:
  写一个脚本
  (1) 提示用户输入一个字符串;
  (2) 判断:
  如果输入的是quit,则退出脚本;
  否则,则显示其输入的字符串内容;

  作业:10:写一个脚本,打印2^n表;n等于一个用户输入的值;
  利用sum作为输出,输入数值作为for循环控制

  作业11:写一个脚本,写这么几个函数:函数1、实现给定的两个数值的之和;函数2、
  取给定两个数值的最大公约数;函数3、取给定两个数值的最小公倍数;关于函数的选定、
  两个数值的大小都将通过交互式输入来提供。
gcd最大公约数    gbs最小公倍数=a*b/最大公约数  第一:创建脚本文件
  maxgcd用于计算最小公倍数时,调用gcd函数保存的变量
  三个函数分为按照1,2,3进行数字选择

  第二:功能函数:
  最大公约数利用until循环进行判断,首先判断是否第一个数字大于
  第二个数字,当第一个数字小于第二个数字时进行数字调换。
  然后利用until判断,当余数为0时退出循环,同时进行数字交换。
  计算完成将最大公约数赋值给maxgcd变量。
  当调用最大倍数时,调用gcd函数,取得maxgcd值。变将最大公
  公约数的输出到/dev/null中。同时根据最大公约数与最大公倍数的公式
  进行计算。



页: [1]
查看完整版本: 20150913 Linux Shell-linux学习点滴