shell编程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell编程相关的知识,希望对你有一定的参考价值。


博主名:  李常明


博文地址: http://keep88.blog.51cto.com

此笔记出自老男孩书籍:   跟老男孩学linux运维  shell编程实战

    shell变量知识进阶与实践

1、shell中的特殊位置参数变量:


位置变量                        作用说明
$0获取当前执行的shell脚本的文件名,如果执行脚本包含了路径,会输出脚本路径
$nn=1..9  获取当前执行的shell脚本的第n个参数值,n为0时,输出脚本文件名,n>9 时,必须用大括号括起来,如${10}
$#获取当前执行的shell脚本后面接的参数的总个数
$*获取当前shell脚本所有传参的参数,如果给$*加上双引号,例:"$*"则会将所有的参数视为单个字符串,如 "$1 $2 $3....."
[email protected]获取当前shell脚本所有传参的参数,如果给[email protected]加上双引号,例:"[email protected]"则会将所有的参数视为不同的独立字符串,如“$1” "$2"  "$3" ...



例如:

1)、$n的使用:n为{1..15}

小技巧:
[[email protected] test]# echo \${1..15}
$1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15  

[[email protected] test]# echo \a{1..10}
a1 a2 a3 a4 a5 a6 a7 a8 a9 a10        #>== 利用此技巧可以快速输出有规律的字符串

 
[[email protected] test]# pwd
/root/test
[[email protected] test]# vim t1.sh 
[[email protected] test]# cat t1.sh 
echo $1
[[email protected] test]# sh t1.sh  test
test
[[email protected] test]# sh t1.sh  zhangsan  lisi
zhangsan

[[email protected] test]# vim t1.sh
[[email protected] test]# cat t1.sh 
echo $1 $2 $3
[[email protected] test]# sh t1.sh zhangsan wangwu lisi
zhangsan wangwu lisi

需注意:

  当参数大于9时,必须用${10} ${11} ${12}.....${15} 使用大括号括起来

2)、$0的使用:

[[email protected] test]# vim t2.sh
[[email protected] test]# cat t2.sh 
echo $0
[[email protected] test]# sh t2.sh
t2.sh
[[email protected] test]# sh t2.sh  zhangsan
t2.sh

注:
  列举两个命令的使用
     1)、dirname和basename
         dirname: 获取路径
         basename:获取文件名
     [[email protected] test]# dirname /root/test/t1.sh
       /root/test
     [[email protected] test]# basename /root/test/t1.sh
       t1.sh

3)、$#的使用:

[[email protected] test]# vim t2.sh 
[[email protected] test]# cat t2.sh 
echo $#
[[email protected] test]# sh t2.sh zhangsan lisi wangwu test1 test2
5

4)、$*  [email protected]  "$*"  "[email protected]"的区别:

结合上述概念,举例分析这四个区别:

1)、使用set设置位置参数(同命令行脚本的传参)
[[email protected] ~]# set -- "I am" smart boy.
[[email protected] ~]# echo $#
3
[[email protected] ~]# echo $1
I am
[[email protected] ~]# echo $2
smart
[[email protected] ~]# echo $3
boy.
2)、测试$*和[email protected],没有带双引号
[[email protected] ~]# echo $*
I am smart boy.
[[email protected] ~]# echo [email protected]
I am smart boy.
使用for循环输出所有参数:  
[[email protected] ~]# for i in $*;do echo $i;done
I
am
smart
boy.
[[email protected] ~]# for i in [email protected];do echo $i;done
I
am
smart
boy.
3)、测试"$*" 和 "[email protected]" ,注意使用了双引号
[[email protected] ~]# echo "$*"
I am smart boy.
[[email protected] ~]# echo "[email protected]"
I am smart boy.
使用for输出所有参数:
[[email protected] ~]# for i in "$*";do echo $i;done
I am smart boy.
[[email protected] ~]# for i in "[email protected]";do echo $i;done
I am
smart
boy.

小结:
  回顾开头我们写的概念分析:
  $*和[email protected]不加引号,输出所有参数,在for语句中,如果有空格分隔的字符串,会拆分输出
  $*和[email protected]都加上引号,例"$*" "[email protected]",此时区别:
    $* 会将所有参数,作为完整的字符串输出,如上所示
    [email protected] 会将所有参数,作为独立的单个字符输出,如果有空格分隔的字符串,不会拆分输出,作为独立的单个字符输出.

注释:
  set 和eval命令的使用详解:
  set可以同命令行一样,可以传参
  eval命令:首先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实现其功能的变量。该命令对变量进行两次扫描。这些需要进行两次扫描的变量有时被称为复杂变量
  例如:
[[email protected] ~]# A="cat t1.sh"
[[email protected] ~]# echo $A
cat t1.sh
[[email protected] ~]# eval $A  #>==  此时eval命令对变量进行置换,还执行了其中的命令
I am smart boy.

set与eval的使用,在编写脚本会用到的例子:
例1)、
[[email protected] ~]# Number=$(set -- $(cat t4.sh); eval "echo \$$#")
注释:  set 设置传入的参数,    eval进行两次扫描,  $#:输出所有的位置参数总数,
         $$#:将总数,也就是最后一个位置参数的值,赋值给Number
[[email protected] ~]# echo $Number
5
例2)、
[[email protected] ~]# runlevel
N 5
[[email protected] ~]# Runlevel=$(set -- $(runlevel);eval "echo \$$#")
[[email protected] ~]# echo $Runlevel
5

2、shell进程中的特殊状态变量:

$?   获取执行上一个指令的执行状态返回值(0为成功,非0表示失败)

3、bash Shell内置变量命令:

1)、echo参数
echo参数选项说明
-n不换行输出内容
-e

解析转义字符

转移字符:
\n换行
\t制表符
\r回车
\b退格
\v纵向制表符


2)、eval命令使用

[[email protected] ~]# cat t1.sh
echo \$$#

[[email protected] ~]# sh t1.sh  arg1 arg2
$2     #>== $#:输出位置参数总数2   $$#:$2   echo输出$2
[[email protected] ~]# cat t1.sh 
eval echo \$$#     #>== 加入eval命令,将echo $5  以命令输出结果
[[email protected] ~]# sh t1.sh arg1 arg2 arg3 arg4
arg4

3)、shift

shift命令的主要作用是将位置参数$1,$2等进行左移,即如果位置参数是$3,$2,$1, 那么执行一次shift后,$3 就变成了$2,$2就变成了$1,$1,就消失了。

例如:

[[email protected] ~]# cat t4.sh 
echo $1 $2
if [ $# -eq 2 ];then
  shift
  echo $1;
fi
[[email protected] ~]# sh t4.sh arg1 arg2
arg1 arg2
arg2      #>== 执行shift命令后,arg1 被左移掉了,剩下了新的$1,即arg2

4、Shell变量字串知识及实践

表达式说明
${parameter}返回变量$parameter的内容
${#parameter}返回变量$parameter内容的长度
${parameter:offset}在变量${parameter}中,从位置offset之后开始提取字串到结尾
${parameter:offset:length}在变量${parameter}中,从位置offset之后开始提取长度为length的字串
${parameter#word}从变量${parameter}开头删除最短匹配的word字串
${parameter##word}从变量${parameter}开头删除最长匹配的word字串
${parameter%word}从变量${parameter}结尾开始删除最短匹配的word字串
${parameter%%word}从变量${parameter}结尾开始删除最长匹配的word字串
${parameter/pattern/string}使用string代替第一个匹配的pattern
${parameter//pattern/string}使用string代替所有匹配的pattern

举例说明各内置变量的使用:

1)、${#parameter} :计算长度

[[email protected] ~]# name="lichangming"
[[email protected] ~]# echo ${#name}
11   #>==  正好11个字符”lichangming“

2)、${parameter:offset}: 指定位置之后提取内容到结尾,同python中的切片类似

[[email protected] ~]# name="lichangming"
[[email protected] ~]# echo ${name:3}
hangming
[[email protected] ~]# echo ${name:2}
changming

3)、${parameter:offset:length}  :从位置offset之后开始提取长度为length的字串

[[email protected] ~]# name="lichangming"
[[email protected] ~]# echo ${name:2:7}
changmi   #>==输出第2个位置之后到第7个位置的内容

注:

此上的截取内容方法,同cut -c命令的功能

例如:

[[email protected] ~]# echo $name
lichangming
[[email protected] ~]# echo ${name} | cut -c 2-7
ichang   #>==  cut命令,后接的数字表示:截取2~7个位置的字符

注意和内置变量的区别,内置变量的第一个offset,起始位置为offset之后的内容

4)、${parameter#word} :从开头开始删除最短匹配word字串

[[email protected] ~]# echo $name
lichangming
[[email protected] ~]# echo ${name#l*g}
ming  #>== 匹配了l至g范围的字串,将其删除,注意一定是从头开始匹配,最短匹配

[[email protected] ~]# echo ${name#c*g}
lichangming   #>==c不是从开头匹配的,所以没有找到匹配项,未删除,输出所有

5)、${parameter##word}  :删除从头开始最长匹配

[[email protected] ~]# name="lichangmingcming"
[[email protected] ~]# echo $name
lichangmingcming
[[email protected] ~]# echo ${name##l*c}
ming    #>== 最长匹配,匹配了lichangmingc,将其删除,剩下ming

看看最短匹配删除的结果:
[[email protected] ~]# echo ${name#l*c}
hangmingcming  #>==最短匹配,匹配了lic,删除

以上匹配删除,都是从头开始删除。

6)、${parameter%word}:从末尾删除最短匹配

7)、${parameter%%word}: 从末尾删除最长匹配

例如:

[[email protected] ~]# echo $name
lichangmingcming
[[email protected] ~]# echo ${name%i*g}
lichangmingcm
[[email protected] ~]# echo ${name%%i*g}
l
[[email protected] ~]# echo ${name%%c*m}
lichangmingcming
[[email protected] ~]# echo ${name%%m*g}
lichang

注意:

从末尾匹配,指第一个值与末尾g 范围的字串,在上述例子中,c*m, 开头为c,中间为任意值,末尾为m,则未找到匹配结果,输出了所有,所以,一定谨记是第一个值与末尾匹配。

8)、${parameter/pattern/string}  :将string替换第一匹配到的模式pattern

[[email protected] ~]# name="li2chang3ming4hehe8"
[[email protected] ~]# echo $name
li2chang3ming4hehe8
[[email protected] ~]# echo ${name/3*4/test}
li2changtesthehe8

9)、${parameter//pattern/string} :将string替换所有匹配到的模式pattern

[[email protected] ~]# name="zhangsan lisi wangwu zhangsan liming"
[[email protected] ~]# echo $name
zhangsan lisi wangwu zhangsan liming
[[email protected] ~]# echo ${name//zhangsan/someone}
someone lisi wangwu someone liming

注:

 使用以上的方法,批量修改文件名

1)、生成测试文件:

[[email protected] test]# pwd
/root/test
[[email protected] test]# ls
[[email protected] test]# touch \smart_t{1..9}.sh
[[email protected] test]# ls
smart_t1.sh  smart_t3.sh  smart_t5.sh  smart_t7.sh  smart_t9.sh
smart_t2.sh  smart_t4.sh  smart_t6.sh  smart_t8.sh

批量改名: 将smart_t*.sh改为silly_t*.sh

[[email protected] test]# ls
smart_t1.sh  smart_t3.sh  smart_t5.sh  smart_t7.sh  smart_t9.sh
smart_t2.sh  smart_t4.sh  smart_t6.sh  smart_t8.sh

[[email protected] test]# for i in `ls *.sh`;do mv $i `echo ${i//smart/silly}`; done
[[email protected] test]# ls
silly_t1.sh  silly_t3.sh  silly_t5.sh  silly_t7.sh  silly_t9.sh
silly_t2.sh  silly_t4.sh  silly_t6.sh  silly_t8.sh

此方法为使用变量的字串替换 来实现的改名方法。


2)、使用rename命令改名:

[[email protected] test]# rename "smart" "silly"  /root/test/*.sh
[[email protected] test]# ls
silly_t1.sh  silly_t3.sh  silly_t5.sh  silly_t7.sh  silly_t9.sh
silly_t2.sh  silly_t4.sh  silly_t6.sh  silly_t8.sh


3)、for循环结合sed实现批量改名:

[[email protected] test]# ls
silly_t1.sh  silly_t3.sh  silly_t5.sh  silly_t7.sh  silly_t9.sh
silly_t2.sh  silly_t4.sh  silly_t6.sh  silly_t8.sh

[[email protected] test]# for i in `ls *.sh`;do mv $i `echo $i | sed s/silly/smart/g`;done
[[email protected] test]# ls
smart_t1.sh  smart_t3.sh  smart_t5.sh  smart_t7.sh  smart_t9.sh
smart_t2.sh  smart_t4.sh  smart_t6.sh  smart_t8.sh




本文出自 “keep常明” 博客,请务必保留此出处http://keep88.blog.51cto.com/11829099/1930977

以上是关于shell编程的主要内容,如果未能解决你的问题,请参考以下文章

代码片段:Shell脚本实现重复执行和多进程

Linux bash基础特性二

VSCode自定义代码片段——JS中的面向对象编程

VSCode自定义代码片段9——JS中的面向对象编程

使用 Pygments 检测代码片段的编程语言

面向面试编程代码片段之GC