把懂的一点shell知识,汇总一下,以便自己以后学习,查找~

shell引号:

名称解释
单引号所见即所得:将单引号内的所有内容都原样输出,或者单引号里面看到的是什么
就会输出什么
双引号把双引号内的所有内容都输出出来:内容中有命令(用反引号)、变量、特殊转义
符号等,会先把变量、命令、转义字符解析出结果,然后再输出最终内容
无引号将内容输出,会将含有空格的字符串视为一个整体输出,如果内容中有命令(反
引号)、变量等,会先把变量、命令解析出结果,然后再输出最终内容,如果字符
串中带有空格等特殊字符,则不能完整的输出,需要加双引号,一般连续的字符串,
数字,路径等可以不加任何引号,无引号的情况,最好用双引号替代
反引号
``,一般用于引命令,窒息的时候命令会被执行
提示:某些语言可能不适合,例如:awk


位置变量:

$# 获取当前执行的shell脚本后面接的参数的总个数

$0 获取当前执行的shell脚本的文件名,如果执行脚本带路径,那么就包括脚本路径

$n 获取当前执行的shell脚本的第n个参数值,当n大于10时,需要用大括号括起来${10},参数以空格隔开



进程状态变量

$$ 获取当前shell脚本的进程号(PID)

$!    执行上一个指令的PID

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


#!/bin/sh

#no1

if [ $# -ne 1 ] 

   then

   echo "USAGE:/data/3306/$0 {start|stop}"

   exit 1

fi

#no2

if [ "$1" == "start" ] 

  then

  /bin/sh /application/mysql/bin/mysqld_safe --defaults-file=/data/3306/my.cnf 2>&1 > /dev/null &

  exit 0

fi

#no3

if [ "$1" == "stop" ]

  then

  mysqladmin -u root -poldboy123 -S /data/3306/mysql.sock shutdown

  exit 0

fi

#!/bin/sh
#no.1 judge arg nums.
[ $# -ne 2 ]&&{
  echo "USAGE:"$0" num1 num2"
  exit 1
}
#no.2 judge if int.
expr $1 + $2 &>/dev/null
[ $? -ne 0 ]&&{
 echo "pls input two nums:"
 exit 2
}

#no.3  compare two int.
[ $1 -lt $2 ]&&{
  echo "$1<$2"
  exit 0
}

[ $1 -eq $2 ]&&{
  echo "$1=$2"
  exit 0
}
[ $1 -gt $2 ]&&{
  echo "$1>$2"
  exit 0
}
#!/bin/bash
a=$1
b=$2
echo "a-b =$(( $a - $b ))"
echo "a+b =$(( $a + $b ))"
echo "a*b =$(( $a * $b ))"
echo "a/b =$(( $a / $b ))"
echo "a**b =$(( $a ** $b ))"
echo "a%b =$(( $a % $b ))"



逻辑操作符

在[ ] 和test中使用的操作符在` `和(( ))中使用的操作符说明
-a&&and,与,两端都威震,结果为真
-o||or,或,两端一个为真,结果为真
!!not,非,两端相反,结果为真


二元比较操作符

在[ ]已经test中使用的比较符号在(( ))和` `中使用的比较符号说明
-eq==或=相等,equal
-ne!=不相等,not equal
-gt>大于,greater than
-ge>=大于等于,greater equal
-lt<小于,less than
-le<=小于等于,less equal

=和!= 也可在[] 中使用,但在[]中使用包含>和<的符号时,需要用反斜线转义,不转义结果可能有误



三种计算字符长度的方法:

[root@zabbix ~]# John="I am John"  

[root@zabbix ~]# expr length "$John"

9

[root@zabbix ~]# echo $John|wc -L

9

[root@zabbix ~]# echo ${#John}

9


例1:

for n in I am John welcome to ucloudlink

do

  if [ ${#n} -lt 6 ]

  then

    echo $n

  fi

done


比较三种方法的效率:

[root@zabbix ~]# chars=`seq -s " " 100`

[root@zabbix ~]# echo $chars

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

[root@zabbix ~]# echo ${#chars}

291

[root@zabbix ~]# echo $(expr length "$chars")

291

[root@zabbix ~]# echo ${chars} |wc -L

291

[root@zabbix ~]# time for i in $(seq 1111); do count=`echo ${chars} |wc -L`;done;

real    0m2.775s

user    0m0.734s

sys     0m1.657s

[root@zabbix ~]# time for i in $(seq 1111); do count=`echo $(expr length "$chars")`;done;

real    0m3.511s

user    0m0.726s

sys     0m1.797s

[root@zabbix ~]# time for i in $(seq 1111); do count=${#chars};done;

real    0m0.158s

user    0m0.152s

sys     0m0.001s

结论:管道效率低


替换:

表达式说明

${#string}

返回$string的长度
${string:position}在$string中,从位置$position之后开始提取子串
${string:position:length}在$string中,从位置$position之后开始提取长度为$length子串
${string#substring}从变量$string开头开始删除最短匹配$substring子串
${string##substring}从变量$string开头开始删除最长匹配$substring子串
${string%substring}从变量$string结尾开始删除最短匹配$substring子串
${string%%substring}从变量$string结尾开始删除最长匹配$substring子串
${string/substring/replace}使用$replace,来替代第一个匹配的$substring
${string/#substring/replace}如果%string前缀匹配$substring,就用$replace来代替匹配$substring,第一个匹配的$substring
${string/%substring/replace}如果%string后缀匹配$substring,就用$replace来代替匹配$substring,最后一个匹配的$substring

小结:#开头删除匹配最短

          ##开头删除匹配最长

          %结尾删除匹配最短

         %%结尾删除匹配最长


变量替换表:

运算符号替换
${value:-word}

如果变量名存在且非null,则返回变量的值。否则,返回word字符串

用途:如果变量未定义,则返回默认值

例:${value:-word},如果value未定义,则表达式的值为word

${value:=word}

如果变量名存在且非null,则返回变量的值。否则,设置这个变量为word,并返回其值

用途:如果变量未定义,则设置变量为默认值,并返回默认值。

例:${value:=word},如果value未定义,则设置value值为word,返回表达式的值也为word


expr只能进行整数运算

[root@zabbix ~]# cat judge_int.sh

read -p "Pls input:" a

expr $a + 1 &>/dev/null

[ $? -eq 0 ] && echo int || echo chars



awk也可以计算小数

[root@zabbix ~]# echo "5.5 5.6"|awk '{print ($2-$1)/5}'

0.02

bc既能计算整数,又能计算小数

[root@zabbix ~]# echo "`seq -s '+' 10`="$((`seq -s "+" 10`))

1+2+3+4+5+6+7+8+9+10=55


常用字符串测试操作符说明
-z "字符串"若串长度为0则为真,-z可以理解为zero
-n "字符串"若串长度不为0则为真,-n可以理解为no zero
"串 1”=“串 2”若串1等于串2则为真,可使用“==”代替“=”
"串 1”!=“串 2”若串1不等于串2则为真,可使用“!==”代替“!=”

注意:以上表格中的字符串测试操作符号务必要用“”引起来

          字符串之间比较,比较符号两边最好有空格


整数比较,推荐下面方法:

[ $num1 -eq $num2 ]    <<注意空格

(($num1>$num2))        <<无需空格


read -p "提示"

-t 超时


特殊写法:

if [ -f "$file1" ];then echo 1; fi相当于:[ -f "$fil1" ]&& echo 1

if [ -f "$file1" ]

    then 

        echo 1

fi


grep精确过滤

[root@zabbix ~]# cat John.log 

200

0200

2000

[root@zabbix ~]# grep "\b200\b" John.log 

200

[root@zabbix ~]# grep -w "200" John.log     

200

[root@zabbix ~]# grep -x "200" John.log  

200

[root@zabbix ~]# grep  "^200$" John.log   

200


shell输入错误操作,回退:

shift  + delete

ctrl + u


sh while.sh &把脚本while.sh放到后台执行
ctrl+c停止执行当前脚本或任务
ctrl+z暂停执行当前脚本或任务
bg把当前脚本或任务放到后台执行,backgroud
fg当前脚本或任务拿到前台执行,如果有多个任务,可以fg加任务编号调出,如fg 1                    frontground
jobs查看当前执行的脚本或任务
kill

[root@zabbix ~]# jobs

[1]-  Running                 sh while.sh &

[2]+  Running                 sh while.sh &

[root@zabbix ~]# kill %2

[root@zabbix ~]# jobs   

[1]-  Running                 sh while.sh &

[2]+  Terminated              sh while.sh

pstree:显示进程状态树

nice:改变优先权

nohup:用户退出系统后任然可以继续工作

pgrep:查找匹配条件的进程

strace:跟踪一个进程的系统调用情况

ltrace:跟踪进程调用库函数的情况

vmstat:报告虚拟内存统计信息


top命令,前五行是系统整体的统计信息,第六行开始为具体的进程统计信息:

top - 11:29:28 up 2 days,  4:28,  1 user,  load average: 0.01, 0.08, 0.03

#同uptime结果,该项显示当前时间(11:29:28),系统运行时间(up 2 days,  4:28),当前登录用户数(1 user)最近1分,5分,15分的三个平均负载值(load average: 0.01, 0.08, 0.03)

Tasks: 1244 total,   1 running, 1243 sleeping,   0 stopped,   0 zombie

#processess自最近一次刷新依赖的运行进程总是(1244 total),进程被分为正在运行的(1 running),休眠的(1243 sleeping),停止的( 0 stopped),僵尸的( 0 zombie)

Cpu(s):  1.5%us,  0.7%sy,  0.0%ni, 97.3%id,  0.5%wa,  0.0%hi,  0.0%si,  0.0%st

#CPU states显示用户( 1.5%us),系统(0.7%sy),优先级进程(只有优先级为负的列入考虑)(0.0%ni)闲置(97.3%id),等待(0.5%wa,)等情况所占用CPU的百分比。优先级进程所消耗的时间也被列入到用户和系统的时间中,所以总的百分比将大于100%

Mem:  16336324k total, 16154176k used,   182148k free,   184208k buffers

#Mem内存使用统计,其中包括总的物理内存总量(16336324k total),已使用的物理内存总量(16154176k used),可用于交换内存(182148k free),用作内存缓存的内存量(184208k buffers)

Swap:  8392696k total,     5808k used,  8386888k free, 11161972k cached

#swap交换分析统计,其中包括总的交换分区总量(8392696k total)已用交换内存量(5808k used,),可用交换内存( 8386888k free),缓存的内存总量(11161972k cached)


top命令参数,按TMP1记

M根据驻留内存大小进行排序
P根据CPU使用百分比大小进行排序
T根据时间、累计时间进行排序
1(数字)显示多个多核CPU单个状态信息
W当前设置写入~/.toprc文件中
ff添加删除列
oo改变列显示的顺序
h或者?显示帮忙画面



扩展:while按行读文件的方式:

方式1:

exec <FILE

sum=0

while read line

do

cmd

done

方式2:

cat ${FILE_PATH} |while read line

do

cmd

done

方式3:

while read line

do

cmd

done<FILE

从日志计算访问当天流量大小

sum=0

while read line

do

value=`echo $line|awk '{print $10}'`

expr $value +1 &>/dev/null

[ $? -ne 0 ] && continue

((sum+=value))

done<access_2010-12-8.log

echo $sum


while循环:

1、while循环的特长是执行守护进程以及我们希望循环不退出持续执行的情况,用于频率小于1分钟循环处理(crond),其他的while循环几乎都可以被for循环替代

2、case语句可以用if语句替换,一般在系统启动脚本传入少量固定规则字符串,用case语句,其他普通判断用if

3、一句话,if,for语句最常用,其次while(守护进程),case(服务启动脚本)



直接列出变量列表所有元素,打印5、4、3、2、1  需要空格隔开

for num in 5 4 3 2 1

do

echo $num

done

for ip in 10.0.0.18 10.0.0.19

do

echo $ip

done

for num in `seq 10`

for num in {1..10}

for file in `ls`

do

if [ -d $file ];tthen

echo "this is $file fir"

else

echo "this is $file file"

fi

done

for 循环批量改名,三种方法:

ls *.jpg|awk -F "_finished" '{print "mv "$0" " $1$2}'|bash

mv $file `echo $file|sed 's#_finished##g'`

mv $file `echo $file|cut -d . -f1`.jpg

rename "_finished" "" *.jpg


9 9 乘法表

[root@zabbix ~]# cat 1-9.sh 

for a in `seq 1 9`

do

  for b in `seq 1 9`

  do

    if [ $a -ge $b ]

    then

      echo -en "$a x $b = $(expr $a \* $b) "

    fi

  done

echo " "

done


[root@zabbix ~]# sh 1-9.sh 

1 x 1 = 1  

2 x 1 = 2 2 x 2 = 4  

3 x 1 = 3 3 x 2 = 6 3 x 3 = 9  

4 x 1 = 4 4 x 2 = 8 4 x 3 = 12 4 x 4 = 16  

5 x 1 = 5 5 x 2 = 10 5 x 3 = 15 5 x 4 = 20 5 x 5 = 25  

6 x 1 = 6 6 x 2 = 12 6 x 3 = 18 6 x 4 = 24 6 x 5 = 30 6 x 6 = 36  

7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 7 x 4 = 28 7 x 5 = 35 7 x 6 = 42 7 x 7 = 49  

8 x 1 = 8 8 x 2 = 16 8 x 3 = 24 8 x 4 = 32 8 x 5 = 40 8 x 6 = 48 8 x 7 = 56 8 x 8 = 64  

9 x 1 = 9 9 x 2 = 18 9 x 3 = 27 9 x 4 = 36 9 x 5 = 45 9 x 6 = 54 9 x 7 = 63 9 x 8 = 72 9 x 9 = 81  


分库备份

mysql -uroot -pJohn123 -S /data/3306/mysql.sock -e 'show databases;'|sed '1d'|grep -v "_schema"


[root@zabbix ~]# vim bak_by_db.sh

#!/bin/sh

MYUSER=root

MYPASS=John123

SOCKET=/data/3306/mysql.sock

MYCMD="mysql -u$MYUER -p$MYPASS -S $SOCKET"

BAKPATH="/server/backup/$(date +%F)"

[ ! -d $BAKPATH ] && mkdir -p $BAKPATH


for dbname in `$MYCMD -e 'show databases;'|sed '1d'|grep -v "_schema"`

do

  $MYDUMP -B -x --events $dbname|gzip >$BAKPATH/${dbname}.sql.gz

  if [ $? -eq 0 ];then

    echo "$dbname" >>$BAKPATH/${dbname}.log

  fi

done


分库分表备份:

[root@zabbix ~]# cat bak_by_db.sh

#!/bin/sh

MYUSER=root

MYPASS=John123

SOCKET=/data/3306/mysql.sock

MYCMD="mysql -u$MYUER -p$MYPASS -S $SOCKET"

BAKPATH="/server/backup/$(date +%F)"

[ ! -d $BAKPATH ] && mkdir -p $BAKPATH


for dbname in `$MYCMD -e 'show databases;'|sed '1d'|grep -v "_schema"`

do

  for tname in `$MYCMD -e "show tables from $dbname;"|sed 1d`

  do

  $MYDUMP -x --events $dbname $tname|gzip >$BAKPATH/${dbname}_${tname}.sql.gz

    if [ $? -eq 0 ];then

      echo "${dbname}_${tname}" >>$BAKPATH/${dbname}.log

    fi

  done

done


文件改名:

[root@zabbix ~]# cat k2.sh

cd /home

for n in `ls *.html`

do

mv $n `echo $n|sed -r 's#^o.*y(.*)html+linux\1HTML#g'`

done

自定义生成用户,密码

for n in `seq -2 10`

do

pass=`echo $RANDOM|md5sum|cut -c 2-9`

useradd oldboy$n && \

echo $pass|passwd --stdin oldboy$n

echo -e "oldboy$n \t $pass" >> /tmp/user.log

done


获取随机数方法:

echo $RANDOM

RANDOM范围0-32767

echo "$RANDOM oldboy"|md5sum

openssl rand -base64 65|cut -c 30-40

时间序列

date +$s%N

head /dev/urandom|cksum

cat /proc/sys/kernel/random/uuid

yum install expect -y

mkpasswd -1 8

chpasswd批量生成用户密码

1.log

liuxia:12345

lixiang:19876

chpasswd <1.log

用户必须存在



命令说明
break nn表示跳出循环的层数,如果省略n表示跳出整个循环
continue nn表示推到第n层继续循环,如果省略n表示跳过本次循环,忽略本次循环的剩余代码,进入循环的下一次循环
exit n退出当前shell程序,n为返回值。n也可以省略,再下一个shell里面$?接收这个n的值
return n用于在函数里,作为函数的返回值,用于判断函数执行是否正确
结论:break continue exit 一般用于循环结构中控制循环的走向


数组:

[root@zabbix ~]# array=(1 2 3)

[root@zabbix ~]# echo ${#array[@]} 

3

[root@zabbix ~]# echo ${#array[*]}

3

[root@zabbix ~]# echo ${array[0]} 

1

[root@zabbix ~]# echo ${array[1]}

2

[root@zabbix ~]# echo ${array[2]}

3


[root@zabbix ~]# vim 1.sh

array=(1 2 3)

for ((i=0;i<${#array[*]};i++))

do

  echo ${array[i]}

done

echo ===================

for i in ${array[*]}

do

  echo $i

done


数组增删

[root@zabbix ~]# echo ${array[@]}

1 2 3

[root@zabbix ~]# array[3]=4

[root@zabbix ~]# echo ${array[@]}

1 2 3 4

[root@zabbix ~]# unset array[2]

[root@zabbix ~]# echo ${array[@]}

1 2 4


数组定义:

静态数组array=(1 2 3)

动态数组array=($(ls))

打印:

${array[@]}或${array[*]} 打印所有元素

${#array[@]}或${#array[*]}打印数组长度

${array[i]} 打印单个元素,i是数组下标。


函数:

#!/bin/bash
john(){
   echo "I am john."
}
function lili(){
   echo "I am lili."
}
john

lili


检查网站状态

function check_url(){
  wget --spider -q -o /dev/null --tries=1 -T 5 $1
  if [ $? -eq 0 ]
   then
     echo "$1 is yes."
  else
    echo "$1 is no."
  fi
}


字体颜色

#!/bin/sh
RED_COLOR='\E[1;31m'
GREEN_COLOR='\E[1;32m'
YELLOW_COLOR='\E[1;33m'
BLUE_COLOR='\E[1;34m'
RES='\E[0m'
echo -e "$RED_COLOR John$RES"

echo -e "$YELLOW_COLOR Lili$RES"


#!/bin/sh
add(){
RED_COLOR='\E[1;31m'
GREEN_COLOR='\E[1;32m'
YELLOW_COLOR='\E[1;33m'
BLUE_COLOR='\E[1;34m'
FLASH_COLOR='\33[5m'
RES='\E[0m'
case "$1" in
  red|RED)
         echo -e "$RED_COLOR $2 $RES"
         ;;
  green|GREEN)
         echo -e "$GREEN_COLOR $2 $RES"
         ;;
  yellow|YELLOW)
         echo -e "$YELLOW_COLOR $2 $RES"
         ;;
  blue|BLUE)
         echo -e "$BLUE_COLOR $2 $RES"
         ;;
         *)
         echo "plu use:{red|green|yellow|blue} {chars}"
         exit
esac
}

menu(){
cat <<END
=================
1.apple
2.pear
3.banana
4.cherry
5.exit
==================
END
}

fruit(){
read -p "pls input the fruit your like:" fruit
case "$fruit" in
    1)
      add red apple
    ;;
    2)
      add green pear
    ;; 
    3)
      add yellow banana
    ;;
    4)
      add blue cherry
    ;;
    5)
      exit
    ;;

    *)
      echo "pls select right num:{1|2|3|4}"
      exit
esac
}

main(){
 while true
 do
  menu
  fruit
 done
}
main


读取输入内容:

#!/bin/sh
read -t 5 -p "Pls input a character:" a
echo "your input is: $a"
read -p "Please input a number:" ans 
case "$ans" in
    1)
            echo  "the num you input is 1"
            ;; 
    2)
           echo "the num you input is 2"
            ;;
    [3-9])
            echo "the num you input is $ans"
            ;;
    *)                                                                                                            
            echo "the num you input must be less 9."
            exit;

esac

#!/bin/sh
#no.1 menu
cat <<EOF
    1.[install lamp]
    2.[install lnmp]
    3.[exit]
EOF
#no.2
read -t 20 -p " pls input the num you want:" num
[ "$num" != "1" -a  "$num" != "2" -a  "$num" != "3" ]&&{
 echo "Input error"
 exit
}
#no.3
[ $num -eq 1 ]&&{
 echo "install lamp"
 [ -f /server/scripts/lamp.sh ]&&\
 /bin/sh /server/scripts/lamp.sh
 exit
}
[ $num -eq 2 ]&&{
 echo "install lnmp"
[ -f /server/scripts/lnmp.sh ]&&\
 /bin/sh /server/scripts/lnmp.sh
 exit
}
[ $num -eq 3 ]&&{
 echo "bye!"
 exit
}
read -p "Pls input:" a
expr $a + 1 &>/dev/null
[ $? -eq 0 ] && echo int||echo chars




shell日志分级别输出函数
#!/bin/bash
#可将log函数单独放一个文件,通过.命令引入,这样就可以共用了
#. spacer.giflog.sh 
#设置日志级别
loglevel=0 #debug:0; info:1; warn:2; error:3
logfile=$0".log"
function log {
        local msg;local logtype
        logtype=$1
        msg=$2
        datetime=`date +'%F %H:%M:%S'`
        #使用内置变量$LINENO不行,不能显示调用那一行行号
        #logformat="[${logtype}]\t${datetime}\tfuncname:${FUNCNAME[@]} [line:$LINENO]\t${msg}"
        logformat="[${logtype}]\t${datetime}\tfuncname: ${FUNCNAME[@]/log/}\t[line:`caller 0 | awk '{print$1}'`]\t${msg}"
        #funname格式为log error main,如何取中间的error字段,去掉log好办,再去掉main,用echo awk? ${FUNCNAME[0]}不能满足多层函数嵌套
        {   
        case $logtype in  
                debug)
                        [[ $loglevel -le 0 ]] && echo -e "\033[30m${logformat}\033[0m" ;;
                info)
                        [[ $loglevel -le 1 ]] && echo -e "\033[32m${logformat}\033[0m" ;;
                warn)
                        [[ $loglevel -le 2 ]] && echo -e "\033[33m${logformat}\033[0m" ;;
                error)
                        [[ $loglevel -le 3 ]] && echo -e "\033[31m${logformat}\033[0m" ;;
        esac
        } | tee -a $logfile
}
#以下为测试
debug () {
        log debug "there are $# parameters:$@"
}
info() {
        log info "funcname:${FUNCNAME[@]},lineno:$LINENO"
}
warn() {
        log warn "funcname:${FUNCNAME[0]},lineno:$LINENO"
}
error() {
        log error "the first para:$1;the second para:$2"
}
set -x
debug first second
set +x
info first second
warn first second 
error first second