@perkyoung
2018-04-12T06:33:55.000000Z
字数 5790
阅读 1101
运维
'#'井号
#comment 注释echo "hello"#comment #注意,#和命令不能紧挨着result=$(( 2#101011 )) #不是注释,是数制转换特定的模式匹配也可能用到#
';'命令分隔符,可以在一行写多个命令
echo "hello" ; echo "world"if test $name == 'perkyoung'; thenfi
';;',有时候';'是需要转义的
case name inperkyoung)echo "....";;esac
'.',
类似source命令如果一个文件开头是'.'字符,这个文件是隐藏文件如果是目录,单独的'.'代表当前目录正则表达式中,'.'匹配任何单独的字符
','
let "result=((a=10,15/3))" #链接一系列算数操作,虽然都执行了,但是只有最后一个被返回echo $a #9echo $result #5
'`'
result=`commands` #命令替换,可以将命令的输出赋值给一个变量。关注后面的后置引用,后置标记
:
: #空命令,什么也不敢,也可以理解为和shell的true作用相同。是bash的内建命令,退出码是0echo $?下面是死循环while :do.....done下面和上面相同while truedo...done在if/then中作为占位符if conditonthen :fi清空一个文件: > ./text.txt #相当于 cat /dev/null > ./text.txt,但是这并不会产生一个新的进程,因为:是内建命令/etc/passwd, PATH的分隔符yangpengfei:x:1000:1000:yangpengfei,,,:/home/yangpengfei:/bin/bash
'!'
if grep perkyoung /etc/passwd #取反命令的退出码if $a != 10
'*'
ls * #文件的通配符\d* #正则表达式中,这个表示任何个数字,包括0个* #乘法** #幂运算
'$'
echo $result #引用变量$? #返回码${} #参数替换$*, $@ #位置参数, $* 所有的参数作为一个字符串,$@是每个参数作为一个独立的单词,for i in $@ ;do ....done,使用的时候都被引用起来,只有这样,她俩才会不同shift #去掉$1,$@指向剩余的参数$! #运行在后台的最后一个作业的pid,$_ #保存着之前命令的最后一个参数值$$ #当前进程的pid,一般用来构造唯一临时文件名。
'()'命令组
(a=10; echo $a) 命令组,将括号内的命令列表,作为一个子shell来运行,所以内部的变量更像是一个内部变量,外部的父shell是无法获取里面的变量的Array=(1 3 4 5) #初始化数组
'{xxx,yyy,zzz}'大括号扩展
cat {file1,file2,file3} > file #将三个文件联合起来写到file中,注意,这三个文件中间不能有空格cp file.{txt,backup} #拷贝file.txt,file.backup
'{}'
内部组,其实是创建了一个匿名函数,但是里面的变量对外部还是可见的。与()不同的是,大括号不会开启一个新的shella=123{ a=321 }echo "a=$a" # a=321#代码块与文件重定向#!/bin/bashFILE=./tmp{read line1read line2} < $FILEecho line1echo line2#将一个代码块结果重定向到文件#!/bin/bash{echo ""commands} > file.txt
'&' 后台运行一个命令
ls -l & #有时候在后台运行一个命令,整个脚本就挂起了,解决方案是在接下来一行添加waitwait
'(())'
整数扩展扩展并计算括号内的表达式
'> &> >& >> < <>'
command >filename #重定向到filenamecommand &>filename #重定向stdout,stderr到filenamecommand >&2 #重定向stdout到stderr[i]<>filename #打开filename,读写,如果没有则创建,分配文件描述符i
'[]'
正则,索引if [[ $a > $b ]]thencommandsfi
'\<,\>'
grep '\<perkyoung\>' ./test #单词的边界
'-'
用于重定向stdin或stdout(cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -)等同于 cp -a /source/directory/* /dest/directory
引用变量的值,叫做变量替换 $
result=23 #变量不带$,一般是变量被声明,被赋值,unset,或者exportecho $result #这个这是引用的简写形式,如果遇到什么问题,就需要用${result}了echo "$result" #如果是双引号,则变量的替换是不能被阻止的,又成为部分引用或弱引用echo '$result' #如果是单引号,则变量的替换完全被阻止,成为全引用或者部分引用
举例,赋值和替换
a=332hello=$avariable=value #一定不能有空格,如果是variable =value,将被解释为,variable是一个命令,后面是参数。如果是variable= value将被解释为,执行了一个value命令,并且添加了一个环境变量,该变量的值为空。hello="a b c d" #有空格的时候一定要加引号echo $hello #a b c decho "$hello" #a b c d , 输出结果不同,所以如果是引用变量,则保留空白,如果是变量替换,则不保留空白
let a=16+5 #一般最好加上双引号吧,因为如果是 a +=1,这种,不加引号是不行的for循环赋值read赋值a=`ls -l` 命令赋值,注意在引用a的时候要加上"$a",这样里面的tab都会引用到a=$(ls -l) 这个和上面的几乎一样。只是一种更新的方法
bash是不区分类型的,所有的都是字符串,当然也进行比较操作和整数操作,关键因素是里面是不是全是数字
result=1234tmp=${result/23/bb} #将23替换为bb
环境变量
如果一个脚本要设置一个环境变量, 那么需要将这些变量"export"出来, 也就是需要通知到脚本
本地的环境. 这是export命令的功能.
位置参数
$1,$2,$3......${10},${11} #超过9之后,就需要用大括号了args=$# #参数个数lastargs=${!args} #如果想取得最后一个参数,如果$4代表最后一个,那如何引用这个4呢,就用到了间接引用或者用${!#},注意不是${!$#}shift #除$0外,将所有参数左移,
$
表示不取'\101\102\103\104' 八进制数编码
任何一个函数,或者进程都会返回一个状态吗,例如exit 0,状态吗0-255,如果没有这个exit指令,则退出码是最后一次执行的指令的退出码
if/then来判断命令列表的退出码是否为0,在unix中0代表成功,如果成功的话,则执行接下来的指令
[]
if [ $a -eq $b ] if test $a -eq $b终于明白了,这个是内建命令,和test功能一致,测试内部的比较表达式,根据比较的结果返回一个退出码,0表示真,1表示假
[[]] 扩展测试命令,比[]更通用,&&,||,<,>可以非常正常得出现在其中,不会出现逻辑错误,test也无法胜任这种情况。
if [[ $a == $b ]]
((...)) let
let "1<2" return 0(( 0 && 1 )) #查看算数表达式的结果,如果为非0,则返回退出码0,表示正确(( 0 )) #这个值为0,所以返回错误,也就是返回值为非0的值
if能测试任何命令,不仅仅是中括号中的条件
if grep -q "perkyoung" /etc/passwd 这个太赞了。if echo "hello" | grep -q "./file"a="./aa"b="./bb"if cmp $a $b &> /dev/nullthen反过来,[]也不一定非要用if,[ $a -eq $b ] && commands #这样也行
-e 文件存在-s 文件大小不为0-h 这是一个符号链接-L 同上-S socket-t 被关联到一个终端设备上-g sgid是否被标记在文件上-u suid是否被标记在文件上-O 是否是文件的拥有者-N 从文件上一次被读到现在是否被修改过f1 -nt f2 f1比f2更新f1 -ot f2 f1比f2更旧f1 -et f2 是相同的硬链接
(( n=n+1 ))n=$((n+1))let "n++"let "a+=1"((n++))
<< 左移一位let "value<<=2" 左移两位,并赋值& 按位与&=| 按位或~ 按位反! 按位非^ 按位异或XOR^=
let "t=032" #八进制let "t=0x11" #16进制let "t=2#11" #用11表示一个2进制的书,base#number
内容不少,以后可以当做手册来看
字符串长度
${#string}len=`expr length $string`
匹配字符串开头的子串长度
expr match "$string" '$substring' #$substring是一个正则表达式或 expr "$string" : '$substring'string="abcdABCD123abcABC"len=`expr match "$string" 'abcd[A-Z]*'` #8从头开始匹配了8个字符
索引
expr index $string $substring在string中匹配到的第一次出现substring的位置string="abcdABCD123abcABC"echo `expr index "$string" '[A-Z]*'` #结果为5
提取子串
${string:position} #从position位置开始提取子串,从0开始计数${string:position:length} #string="abcdABCD123abcABC"echo ${string:3:3} #dABecho ${string: -4} ; echo ${string:(-4)}; echo ${string:(-4):3} #从右边截取,截取后四个,注意要有空格或者括号echo ${*:2} #如果不提供变量,则截取的就是命令行的参数,这个是从第二个开始到最后面的参数echo ${@:2}echo ${*:2:3}expr substr $string $position $lengthexpr match "$string" '\($substring\)' #从开头位置匹配substring,substring是一个正则表达式或者expr "$string" : '\($substring\)' #同上
子串消除
${string#substring} #从开头位置节点最短匹配的$substring,这里也是开头位置${string##substring} #从开头位置节点最长匹配的$substring,这里也是开头位置string="abcdABCD123abcABC"echo ${string#a*c} #dABCD123abcABCecho ${string##a*c} #ABC${string%substring} #从结尾,截取最短${string%%substring}#同上,截取最长
子串替换
${string/$substring/$replacement} #使用replacement来替换第一个匹配的substring${string//$substring/$replacement} #使用replacement来替换所有匹配的substring${string/#$substring/$replacement} #如果substring匹配开头的字符,使用replacement来替换开头的串${string/$$substring/$replacement} #如果substring匹配结尾的字符,使用replacement来替换结尾的串
${parameter} #可以和字符串组合起来实用${param=default} #如果变量没有被声明,则值为default${param:=default} #如果变量没有被设置,则值为defaultecho "username=${username=`whoami`}username=echo "username=${username:=`whoami`}${param+alt_value} #如果变量已经被声明,那么值就是后者,否则为null${param:+alt_value} #如果变量已经被设置,则值为后者,否则为null${param?err_msg} #如果变量被声明,就使用设置的值,否则打印err_msg${parma:?err_msg} #如果变量被设置,就使用设置的值,否则打印err_msg: ${HOSTNAME?} ${USER?}
declare -r 创建只读变量-i 创建int类型-a 数组-f 函数-x export变量-x val=$value export变量并且declare可以限制变量的作用域,比如函数内部declare了变量VA,那外部是无法引用该变量的。非declare的变量,在外部是可以的使用的
一个变量的值是另一个变量的名字
a=letter_ofletter_of=z如何通过变量a来获取到z呢?eval a=\$$a #a=z或者 a=${!a}
与let很相似,允许算数扩展和赋值,可以认为是bash使用C语言风格的处理机制
#/bin/bash(( .... ))(( a = 23 )(( a++ ))(( a-- ))(( ++a ))(( t = a<45?7:11 ))