小杨同志

导航

 

特殊字符

'#'井号

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

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

echo "hello" ; echo "world"
if test $name == 'perkyoung'; then
fi

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

case name in
perkyoung)
    echo "...."
;;
esac

'.',

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

','

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

'`'

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

:

: #空命令,什么也不敢,也可以理解为和shell的true作用相同。是bash的内建命令,退出码是0
echo $?

下面是死循环
while :
do
    .....
done

下面和上面相同
while true
do
    ...
done

在if/then中作为占位符
if conditon
then :
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    #引用变量
$?              #返回码
$$              #进程id
${}             #参数替换
$*, $@          #位置参数, $* 所有的参数作为一个字符串,$@是每个参数作为一个独立的单词,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

'{}'

内部组,其实是创建了一个匿名函数,但是里面的变量对外部还是可见的。与()不同的是,大括号不会开启一个新的shell
a=123
{ a=321 }
echo "a=$a" # a=321

#代码块与文件重定向
#!/bin/bash
FILE=./tmp
{
    read line1
    read line2
} < $FILE
echo line1
echo line2

#将一个代码块结果重定向到文件
#!/bin/bash
{
    echo ""
    commands
} > file.txt

'&' 后台运行一个命令

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

'(())'

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

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

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

'[]'

正则,索引
if [[ $a > $b ]]
then
    commands
fi

'<,\>'

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

'-'

用于重定向stdin或stdout
(cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -)
等同于 cp -a /source/directory/* /dest/directory

变量和参数的介绍

变量替换

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

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

举例,赋值和替换

a=332
hello=$a   
variable=value  #一定不能有空格,如果是variable =value,将被解释为,variable是一个命令,后面是参数。如果是variable= value将被解释为,执行了一个value命令,并且添加了一个环境变量,该变量的值为空。

hello="a b  c    d" #有空格的时候一定要加引号
echo $hello #a b c d
echo "$hello"   #a b  c   d , 输出结果不同,所以如果是引用变量,则保留空白,如果是变量替换,则不保留空白

变量的赋值 =

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

bash变量是不区分类型的

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

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

特殊的变量类型

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

位置参数

$1,$2,$3......${10},${11}   #超过9之后,就需要用大括号了

args=$# #参数个数
lastargs=${!args}   #如果想取得最后一个参数,如果$4代表最后一个,那如何引用这个4呢,就用到了间接引用或者用${!#},注意不是${!$#}

shift   #除$0外,将所有参数左移,

引用

$
表示不取\(后面的变量的值 abc=\)'\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 -eq $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/null
then

反过来,[]也不一定非要用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}  #dAB
echo ${string: -4}  ; echo ${string:(-4)}; echo ${string:(-4):3}  #从右边截取,截取后四个,注意要有空格或者括号

echo ${*:2} #如果不提供变量,则截取的就是命令行的参数,这个是从第二个开始到最后面的参数
echo ${@:2}
echo ${*:2:3}   

expr substr $string $position $length

expr match "$string" '\($substring\)'   #从开头位置匹配substring,substring是一个正则表达式
或者expr "$string" : '\($substring\)'     #同上

子串消除

${string#substring} #从开头位置节点最短匹配的$substring,这里也是开头位置
${string##substring} #从开头位置节点最长匹配的$substring,这里也是开头位置

string="abcdABCD123abcABC"
echo ${string#a*c}  #dABCD123abcABC
echo ${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}   #如果变量没有被设置,则值为default
echo "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_of
letter_of=z
如何通过变量a来获取到z呢?
eval a=\$$a #a=z
或者 a=${!a}

$RANDOM产生随机整数

$RANDOM不是常量,是内置函数

双圆括号结构

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

#/bin/bash
(( .... ))
(( a = 23 )
(( a++ ))
(( a-- ))
(( ++a ))
(( t = a<45?7:11 ))
posted on 2015-07-12 01:17  小杨同志  阅读(228)  评论(1)    收藏  举报