[关闭]
@perkyoung 2018-04-12T06:33:55.000000Z 字数 5790 阅读 898

shell编程学习总结-1

运维


特殊字符

'#'井号

  1. #comment 注释
  2. echo "hello"#comment #注意,#和命令不能紧挨着
  3. result=$(( 2#101011 )) #不是注释,是数制转换
  4. 特定的模式匹配也可能用到#

';'命令分隔符,可以在一行写多个命令

  1. echo "hello" ; echo "world"
  2. if test $name == 'perkyoung'; then
  3. fi

';;',有时候';'是需要转义的

  1. case name in
  2. perkyoung)
  3. echo "...."
  4. ;;
  5. esac

'.',

  1. 类似source命令
  2. 如果一个文件开头是'.'字符,这个文件是隐藏文件
  3. 如果是目录,单独的'.'代表当前目录
  4. 正则表达式中,'.'匹配任何单独的字符

','

  1. let "result=((a=10,15/3))" #链接一系列算数操作,虽然都执行了,但是只有最后一个被返回
  2. echo $a #9
  3. echo $result #5

'`'

  1. result=`commands` #命令替换,可以将命令的输出赋值给一个变量。关注后面的后置引用,后置标记

:

  1. : #空命令,什么也不敢,也可以理解为和shell的true作用相同。是bash的内建命令,退出码是0
  2. echo $?
  3. 下面是死循环
  4. while :
  5. do
  6. .....
  7. done
  8. 下面和上面相同
  9. while true
  10. do
  11. ...
  12. done
  13. if/then中作为占位符
  14. if conditon
  15. then :
  16. fi
  17. 清空一个文件
  18. : > ./text.txt #相当于 cat /dev/null > ./text.txt,但是这并不会产生一个新的进程,因为:是内建命令
  19. /etc/passwd PATH的分隔符
  20. yangpengfei:x:1000:1000:yangpengfei,,,:/home/yangpengfei:/bin/bash

'!'

  1. if grep perkyoung /etc/passwd #取反命令的退出码
  2. if $a != 10

'*'

  1. ls * #文件的通配符
  2. \d* #正则表达式中,这个表示任何个数字,包括0个
  3. * #乘法
  4. ** #幂运算

'$'

  1. echo $result #引用变量
  2. $? #返回码
  3. ${} #参数替换
  4. $*, $@ #位置参数, $* 所有的参数作为一个字符串,$@是每个参数作为一个独立的单词,for i in $@ ;do ....done,使用的时候都被引用起来,只有这样,她俩才会不同
  5. shift #去掉$1,$@指向剩余的参数
  6. $! #运行在后台的最后一个作业的pid,
  7. $_ #保存着之前命令的最后一个参数值
  8. $$ #当前进程的pid,一般用来构造唯一临时文件名。

'()'命令组

  1. (a=10; echo $a) 命令组,将括号内的命令列表,作为一个子shell来运行,所以内部的变量更像是一个内部变量,外部的父shell是无法获取里面的变量的
  2. Array=(1 3 4 5) #初始化数组

'{xxx,yyy,zzz}'大括号扩展

  1. cat {file1,file2,file3} > file #将三个文件联合起来写到file中,注意,这三个文件中间不能有空格
  2. cp file.{txt,backup} #拷贝file.txt,file.backup

'{}'

  1. 内部组,其实是创建了一个匿名函数,但是里面的变量对外部还是可见的。与()不同的是,大括号不会开启一个新的shell
  2. a=123
  3. { a=321 }
  4. echo "a=$a" # a=321
  5. #代码块与文件重定向
  6. #!/bin/bash
  7. FILE=./tmp
  8. {
  9. read line1
  10. read line2
  11. } < $FILE
  12. echo line1
  13. echo line2
  14. #将一个代码块结果重定向到文件
  15. #!/bin/bash
  16. {
  17. echo ""
  18. commands
  19. } > file.txt

'&' 后台运行一个命令

  1. ls -l & #有时候在后台运行一个命令,整个脚本就挂起了,解决方案是在接下来一行添加wait
  2. wait

'(())'

  1. 整数扩展
  2. 扩展并计算括号内的表达式

'> &> >& >> < <>'

  1. command >filename #重定向到filename
  2. command &>filename #重定向stdout,stderr到filename
  3. command >&2 #重定向stdout到stderr
  4. [i]<>filename #打开filename,读写,如果没有则创建,分配文件描述符i

'[]'

  1. 正则,索引
  2. if [[ $a > $b ]]
  3. then
  4. commands
  5. fi

'\<,\>'

  1. grep '\<perkyoung\>' ./test #单词的边界

'-'

  1. 用于重定向stdinstdout
  2. (cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -)
  3. 等同于 cp -a /source/directory/* /dest/directory

变量和参数的介绍

变量替换

引用变量的值,叫做变量替换 $

  1. result=23 #变量不带$,一般是变量被声明,被赋值,unset,或者export
  2. echo $result #这个这是引用的简写形式,如果遇到什么问题,就需要用${result}了
  3. echo "$result" #如果是双引号,则变量的替换是不能被阻止的,又成为部分引用或弱引用
  4. echo '$result' #如果是单引号,则变量的替换完全被阻止,成为全引用或者部分引用

举例,赋值和替换

  1. a=332
  2. hello=$a
  3. variable=value #一定不能有空格,如果是variable =value,将被解释为,variable是一个命令,后面是参数。如果是variable= value将被解释为,执行了一个value命令,并且添加了一个环境变量,该变量的值为空。
  4. hello="a b c d" #有空格的时候一定要加引号
  5. echo $hello #a b c d
  6. echo "$hello" #a b c d , 输出结果不同,所以如果是引用变量,则保留空白,如果是变量替换,则不保留空白

变量的赋值 =

  1. let a=16+5 #一般最好加上双引号吧,因为如果是 a +=1,这种,不加引号是不行的
  2. for循环赋值
  3. read赋值
  4. a=`ls -l` 命令赋值,注意在引用a的时候要加上"$a",这样里面的tab都会引用到
  5. a=$(ls -l) 这个和上面的几乎一样。只是一种更新的方法

bash变量是不区分类型的

bash是不区分类型的,所有的都是字符串,当然也进行比较操作和整数操作,关键因素是里面是不是全是数字

  1. result=1234
  2. tmp=${result/23/bb} #将23替换为bb

特殊的变量类型

环境变量
如果一个脚本要设置一个环境变量, 那么需要将这些变量"export"出来, 也就是需要通知到脚本
本地的环境. 这是export命令的功能.

位置参数

  1. $1,$2,$3......${10},${11} #超过9之后,就需要用大括号了
  2. args=$# #参数个数
  3. lastargs=${!args} #如果想取得最后一个参数,如果$4代表最后一个,那如何引用这个4呢,就用到了间接引用或者用${!#},注意不是${!$#}
  4. shift #除$0外,将所有参数左移,

引用

$
表示不取'\101\102\103\104' 八进制数编码

退出码

任何一个函数,或者进程都会返回一个状态吗,例如exit 0,状态吗0-255,如果没有这个exit指令,则退出码是最后一次执行的指令的退出码

条件判断

条件测试结构

if/then来判断命令列表的退出码是否为0,在unix中0代表成功,如果成功的话,则执行接下来的指令

[]

  1. if [ $a -eq $b ] if test $a -eq $b
  2. 终于明白了,这个是内建命令,和test功能一致,测试内部的比较表达式,根据比较的结果返回一个退出码,0表示真,1表示假

[[]] 扩展测试命令,比[]更通用,&&,||,<,>可以非常正常得出现在其中,不会出现逻辑错误,test也无法胜任这种情况。

  1. if [[ $a == $b ]]

((...)) let

  1. let "1<2" return 0
  2. (( 0 && 1 )) #查看算数表达式的结果,如果为非0,则返回退出码0,表示正确
  3. (( 0 )) #这个值为0,所以返回错误,也就是返回值为非0的值

if能测试任何命令,不仅仅是中括号中的条件

  1. if grep -q "perkyoung" /etc/passwd 这个太赞了。
  2. if echo "hello" | grep -q "./file"
  3. a="./aa"
  4. b="./bb"
  5. if cmp $a $b &> /dev/null
  6. then
  7. 反过来,[]也不一定非要用if,[ $a -eq $b ] && commands #这样也行

文件测试操作符

  1. -e 文件存在
  2. -s 文件大小不为0
  3. -h 这是一个符号链接
  4. -L 同上
  5. -S socket
  6. -t 被关联到一个终端设备上
  7. -g sgid是否被标记在文件上
  8. -u suid是否被标记在文件上
  9. -O 是否是文件的拥有者
  10. -N 从文件上一次被读到现在是否被修改过
  11. f1 -nt f2 f1f2更新
  12. f1 -ot f2 f1f2更旧
  13. f1 -et f2 是相同的硬链接

操作符

算数操作符

  1. (( n=n+1 ))
  2. n=$((n+1))
  3. let "n++"
  4. let "a+=1"
  5. ((n++))

位操作符

  1. << 左移一位
  2. let "value<<=2" 左移两位,并赋值
  3. & 按位与
  4. &=
  5. | 按位或
  6. ~ 按位反
  7. ! 按位非
  8. ^ 按位异或XOR
  9. ^=

逻辑操作符

数字常量

  1. let "t=032" #八进制
  2. let "t=0x11" #16进制
  3. let "t=2#11" #用11表示一个2进制的书,base#number

变量重游

内部变量

内容不少,以后可以当做手册来看

操作字符串

字符串长度

  1. ${#string}
  2. len=`expr length $string`

匹配字符串开头的子串长度

  1. expr match "$string" '$substring' #$substring是一个正则表达式
  2. expr "$string" : '$substring'
  3. string="abcdABCD123abcABC"
  4. len=`expr match "$string" 'abcd[A-Z]*'` #8从头开始匹配了8个字符

索引

  1. expr index $string $substring
  2. string中匹配到的第一次出现substring的位置
  3. string="abcdABCD123abcABC"
  4. echo `expr index "$string" '[A-Z]*'` #结果为5

提取子串

  1. ${string:position} #从position位置开始提取子串,从0开始计数
  2. ${string:position:length} #
  3. string="abcdABCD123abcABC"
  4. echo ${string:3:3} #dAB
  5. echo ${string: -4} ; echo ${string:(-4)}; echo ${string:(-4):3} #从右边截取,截取后四个,注意要有空格或者括号
  6. echo ${*:2} #如果不提供变量,则截取的就是命令行的参数,这个是从第二个开始到最后面的参数
  7. echo ${@:2}
  8. echo ${*:2:3}
  9. expr substr $string $position $length
  10. expr match "$string" '\($substring\)' #从开头位置匹配substring,substring是一个正则表达式
  11. 或者expr "$string" '\($substring\)' #同上

子串消除

  1. ${string#substring} #从开头位置节点最短匹配的$substring,这里也是开头位置
  2. ${string##substring} #从开头位置节点最长匹配的$substring,这里也是开头位置
  3. string="abcdABCD123abcABC"
  4. echo ${string#a*c} #dABCD123abcABC
  5. echo ${string##a*c} #ABC
  6. ${string%substring} #从结尾,截取最短
  7. ${string%%substring}#同上,截取最长

子串替换

  1. ${string/$substring/$replacement} #使用replacement来替换第一个匹配的substring
  2. ${string//$substring/$replacement} #使用replacement来替换所有匹配的substring
  3. ${string/#$substring/$replacement} #如果substring匹配开头的字符,使用replacement来替换开头的串
  4. ${string/$$substring/$replacement} #如果substring匹配结尾的字符,使用replacement来替换结尾的串

参数替换

  1. ${parameter} #可以和字符串组合起来实用
  2. ${param=default} #如果变量没有被声明,则值为default
  3. ${param:=default} #如果变量没有被设置,则值为default
  4. echo "username=${username=`whoami`}
  5. username=
  6. echo "username=${username:=`whoami`}
  7. ${param+alt_value} #如果变量已经被声明,那么值就是后者,否则为null
  8. ${param:+alt_value} #如果变量已经被设置,则值为后者,否则为null
  9. ${param?err_msg} #如果变量被声明,就使用设置的值,否则打印err_msg
  10. ${parma:?err_msg} #如果变量被设置,就使用设置的值,否则打印err_msg
  11. : ${HOSTNAME?} ${USER?}

指定变量类型

  1. declare -r 创建只读变量
  2. -i 创建int类型
  3. -a 数组
  4. -f 函数
  5. -x export变量
  6. -x val=$value export变量
  7. 并且declare可以限制变量的作用域,比如函数内部declare了变量VA,那外部是无法引用该变量的。非declare的变量,在外部是可以的使用的

变量的间接引用

一个变量的值是另一个变量的名字

  1. a=letter_of
  2. letter_of=z
  3. 如何通过变量a来获取到z呢?
  4. eval a=\$$a #a=z
  5. 或者 a=${!a}

RANDOM不是常量,是内置函数

双圆括号结构

与let很相似,允许算数扩展和赋值,可以认为是bash使用C语言风格的处理机制

  1. #/bin/bash
  2. (( .... ))
  3. (( a = 23 )
  4. (( a++ ))
  5. (( a-- ))
  6. (( ++a ))
  7. (( t = a<45?7:11 ))

测试印象笔记同步功能

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注