005.shell基础

shell脚本基础

shell脚本可以输入多个命令并处理每个命令的结果。

创建shell脚本时,需要在文件的第一行指定使用的解析器(#!/bin/bash)

通常shell脚本在行里,#号用作注释行,不被执行,第一行是个特例,它指定执行的解析器

vim 第一个脚本文件.sh
#!/bin/bash
# 这是一个demo
date
wc file1
# 执行脚本
sh ***.sh
./***.sh

特殊符号

  1. 反引号

    反引号(``):允许你把shell变量的结果输出赋值给变量

    test=`date`
    echo $test #显示的是时间
    test=`echo "hello world"`
    echo $test
    
  2. 重定向

    重定向符号指向数据流动的方向。

    重定向(>,>>):允许你将某个命令的输入输出重定向到另一个位置

    date > file # 覆盖原有数据
    date >> file # 追加数据
    

    输入重定向(<):将文件内容重定向到命令中

    > wc < file
    > wc <<aa
    > ok
    > world
    > aa
    

  3. 管道

    取代输出重定向到文件件,可以将重定向到另一个命令,称为管道连接。

    管道连接不是一个一个运行的,在系统内部将他们连接起来,一个命令输出的同时,另一个命令同时运行,传输数据不会用的任何中间数据和中间文件

    ls > file
    sort < file
    ls | sort
    

数学运算相关命令

expr:用来处理数学表达式,它可以识别一些不同的数字和字符串操作(操作符两侧的空格及转移)


image.png

image.png
expr 1 + 5

expr 1 \* 5

vim test.sh
#!/bin/bash  #指定解析器
var1=3
var2=2
var3=`expr $var1 \* $var2`
echo $var3

sh test.sh
chmod 777 test.sh
./test.sh

echo $PATH
vim ~/.vimrc
set number #设置行号

#数学表达式简单方法 $[operation]
var2=$[5+2]
echo $var2

shell脚本(条件语句)

if语句运行if定义命令(如果退出状态吗为0,运行then部分命令)

vim test.sh
if date 
then
     #语句块
     echo "running then"
     echo "---------------"
fi
sh test.sh

#多命令用;分割
echo $var1;echo $var2

date
echo $?  #上一个状态退出码

if ssss
then
    #语句块
    echo "running then"
    echo "---------------"
else
    #语句块
    echo 'runing else'
fi

if ssss
then
    #语句块
    echo "running then"
    echo "---------------"
elif date
then
    echo "else"
else
    #语句块
    echo 'runing else'
fi

test命令(数值比较,字符串比较,文件比较)

格式1:test condition
格式2:[ condition ] (左右空格一般都要个加一个空格,否则会报错)


image.png
#!/bin/bash
########################################## #####   **********
#####   **********
#########################################
if test 6 -gt 5
then
    echo "6 > 5"
fi            

if [ 6 -gt 5 ]
then
    echo "6 > 5"
fi   
#不能处理小数
image.png
  1. test的比较会将所有的标点和大写也考虑在内。
  2. 要转义大于小于号,否则会被当为重定向符号
  3. test命令字符串比较会使用标准的ASCII顺序,根据每个字符的ASCII数值来决定排序顺序。
  4. test命令使用标准的数学比较符号来表示字符串的比较,而用文本代码表示数值比较。
 12 if [ aa = aa ]
 13 then
 14     echo "equal"
 15 fi
 16 
 17 user=aaaa
 18 testuser=aaaa
 19 if [ $user != $testuser ]
 20 then
 21     echo "no eque"
 22 else
 23     echo "eque"
 24 fi

if [ aaa \> bbb ]
then
     echo "aaaa>bbbb"
fi

var1=""
if [ -z var1 ]
then 
   echo "是空"
fi
image.png
 27 if [ -d $HOME ]
 28 then
 29     ls $HOME
 30     if [ -r $HOME ]
 31     then
 32         echo "$HOME is read"
 33     fi
 34 else
 35     echo "is not directory"
 36 fi

复合条件

if date && [ -n aaa ]
then
    echo "run"
else
    echo "no run"
fi

if-then语句高级特性

  1. 用于数学表达式的双括号(空格可以省略,不需要转义大于小于等符号)
    (( ))双括号命令允许你将高级数学表达式放入比较中,test命令只允许在比较中进行简单的算术操作

  2. 用于高级字符串处理功能的双方括号(两侧空格必须存在)
    [[ ]] 双方括号支持test命令的特性,并新增了另一个特性模式(正则表达式)匹配.


    image.png
if ((10 ** 2 >90));then
  ((v2= 10 ** 2))
  echo "v2="$v2
fi
 
if [[ $USER = w* ]];then
 echo "yes"
fi

case命令

  • 为了避免在一组可能的值中寻找特定值而写出很长的if-then-else语句,引入case命令
  • case命令会检查单个变量列表格式的多个值.
  • 通过竖线操作符来分割模式
  • 星号*会捕获所有跟列出的模式都不匹配的值
  • 每一个语句块一双分号结尾
case $USER in
work333 | work1)
echo "welcome work work1";;
work2)
echo "welcome work2";;
*)
echo "welcome other";;
esac

shell脚本(循环语句for,while,until)

特殊的环境变量IFS, 称为内部字段分隔符(interal field separator) ,IFS环境变量定义了bash shell用作字段分隔符的一系列字符。>set |grep IFS 默认情况下,bash shell会将空格、制表符、换行符定义为字段分隔符。

for test in Alabama Alaska Arizona California
do
   echo "The next is $test"
done

echo $test   #该值会在shell脚本的剩余部分一直保持有效

val="Alabama Alaska Arizona California"
for test in $val   # 从变量读取迭代列表
do       
 echo "The next is $test"
done

# 注意单引号的转义,及元素中带空格的处理
for test in I\'am a boy, "you are a gril"  
do
  echo "The next is $test"
done

#从文件读取迭代列表
for test in `cat bb`;
do    
   echo "The next is $test"
done

for ((i=0;i<10;i++))       #C语言风格的for循环
do
  echo "The next number is $i"
done

for ((a=1,b=10;a<=10,b>2;a++,b--))   #C语言风格的多个条件
do
  echo "$a -  $b"
done

while命令:
允许你在while语句行定义多个测试命令,只有最后一个测试命令的退出状态码会被用来决定什么时候结束循环。

val1=10
while [ $val1 -gt 0 ]
do
  echo $val1
  (( val1-- ))
  #val1=$[$val1-1]
done
 
val1=10
while echo $val1  #定义多个测试命令,只有最后一个测试命令的退出状态码会被用来决定结束循环
[ $val1 -gt 0 ]
do
  echo "This is flag"
  val1=$[$val1-1]
done

until命令:要求你指定一个通常输出非零退出状态码的测试命令,一旦测试命令返回退出状态码0,则循环就结束了。

val1=10
until [ $val1 -eq 0 ]   #until也是支持同时指定多个命令的
do
  echo $val1
  ((val1--))
done

嵌套循环:

for (( a=1;a<=3;a++ )) #嵌套循环
do
  echo "start loop $a"
  for ((b=1;b<=3;b++))
  do
    echo "Inside loop: $b"
  done
done

break和continue命令

for var1 in 1 2 3 4 5 6 7
do
  if [ $var1 -eq 5 ]
  then
    break         #跳出循环
  fi
  echo "echo $var1"
done
var1=10
 
while [ $var1 -gt 0 ]
do
  if [ $var1 -eq 5 ]
  then
      break
  fi
  echo "while echo $var1"
  ((var1--))
done


for ((a=1;a<4;a++))
do
  echo "Outer loop :$a"
  for ((b=1;b<100;b++))
  do
     if [ $b -eq 5 ];then
        break         #跳出最靠近的循环
     fi
     echo "         Inner loop: $b"
  done
done
echo "----------"
#跳出外部循环
for ((a=1;a<4;a++))
do
  echo "Outer loop :$a"
  for ((b=1;b<100;b++))
  do
     if [ $b -eq 5 ];then
        break 2        #n指明break要跳出的层级,若不指明n则 默认层级为1
     fi
     echo "         Inner loop: $b"
  done
done



for ((var1=1;var1<15;var1++))
do
   if [ $var1 -gt 5 ] && [ $var1 -lt 10 ]
   then
       continue          #continue设置提早结束执行循环内部的命令,但并不终止循环
   fi
   echo "Iteration number: $var1"
done
 
for ((a=1;a<=5;a++))
do
  echo "Iteration $a"
  for ((b=1;b<3;b++))
  do
    echo " b= $b"
    if [ $a -gt 2 ] && [ $a -lt 4 ]
    then
        continue 2  #指定要继续的循环层级n
    fi
    var3=$[ $a*$b ]
    echo "   The result of $a * $b is $var3"
  done
done


shell脚本高级部分(函数定义,函数参数,函数变量)

函数是可以起个名字并在代码中任何位置重用的代码块。你要在脚本中使用该代码块时,只要使用分配的函数名就行了

  1. 函数定义要在使用函数前
  2. 如果你重定义了函数,新定义会覆盖原来函数的定义,而不会产生任何错误消息。
  3. 默认情况下,函数的退出状态码是函数中最后一条命令返回的退出状态码
function f1 {   #function定义的函数 函数名和花括号之间必须加入空格,否则报错
  echo "This is an example of a function"
}
f2(){
  echo "This is second example"
}
 
for ((a=1;a<10;a++))
do
  f1        #注意函数定义要在使用函数前
  f2
done

$?的说明
$?变量会返回执行的最后一条命令的退出状态码
可以在函数中指定return返回的退出状态码,要注意退出状态码的值必须在0~255之间, 任何大于256的值都会返回一个错误的值

f3(){
 echo "f3"
 ls badfile  #函数的退出状态码是函数中最后一条命令返回的退出状态码
}
f3
echo "the function f3 returncode="$?
 
f4(){
  var1=3
  return $[$var1 * 3]   #return指定函数的退出状态码
}
f4
echo $?

参数:函数使用标准的参数环境变量来代表命令行上传给函数的参数,函数名会在$0变量中定义,函数命令行上的任何参数都会通过
$1、$2等定义,也可以用特殊变量$#来判断传给函数的参数数目。

#向函数传递参数     与向脚本传递参数使用方式相同
addem(){
 if [ $# -eq 0 ] || [ $# -gt 2 ]
 then
    echo -1
 elif [ $# -eq 1 ]
 then
     echo $1
 else
     echo $[$1+$2]
fi
}
addem 8 9
addem 10
addem

函数中的变量:全局变量,局部变量

  • 默认情况下,在脚本中定义的任何变量都是全局变量,可以在函数内正常访问,如果全局变量在函数内被赋予了新值,那么在脚本中引用该变量时,新值依然有效。
  • 在函数内部声明局部变量 ,只需要在变量前加入 local关键字。 局部变量保证了变量只局限在该函数中,如果脚本中在该函数之外有相同名字的变量,那么shell将会保持这两个变量的值独立。
f6(){
 temp=$[$value+5]
}
temp=4
value=6
f6
if [ $temp -gt $value ];then
 echo "temp is large"
else
 echo "temp is smaller"
fi


f7(){
 local temp=$[$value+5]
}
temp=4
value=6
f7
if [ $temp -gt $value ];then
 echo "temp is large"
else
 echo "temp is smaller"
fi

shell库文件

在单个脚本中,使用函数可以省去一些键入的工作,但是在多个脚本之间如何使用同一个代码块呢,显然,在每个脚本中都定义同样的函数而只使用一次会比较麻烦。

  • shell创建库文件
  • shell函数的作用域:shell只对定义它的shell会话有效。
  • source会在当前的shell上下文中执行命令,而不是创建一个新的shell来执行命令。
  • source命令有个快捷别名,称作点操作符 .
vim init.sh
#!/bin/bash
f(){
    echo "okokokok"
}
vim test7.sh
#!/bin/bash
f
source init.sh #可以全路径引用
f

vim test7.sh
#!/bin/bash
f   #因为作用域问题,会报错
. init.sh
f

exit #退出脚本命令

工作中常用小工具

防止误删工具(本质是移动目录)

vim ~/.bashrc
trash(){
  mv $1 ~/Trash1
}
alias rm="trash"

批量修改数据并保存日志

vim  exe_targetday.sh
#!/bin/bash
set -x
source init.sh
startDay=$1
endDay=$2
if [ -z ${startDay} ]
then startDay=`date -d "-1 day" +"%Y%m%d"`
fi
 
if [ -z ${endDay} ]
then endDay=${startDay}
fi
while [ ${startDay} -le ${endDay} ]
do
  echo ${startDay}
  xqe -e "use namespace fsg_ns;alter table base_data.wappass_udi drop if exists partition(dt='${startDay}');alter table base_data.wappass_udi add partition(dt='${startDay}') location 'afs://xingtian.afs.baidu.com:9902/app/passport_log/queryengine/pass_data/wappass_udi/dt=${startDay}';" &> ${startDay}.log &
  startDay=`date -d "${startDay} 1 day" +"%Y%m%d"`
done
wait
echo "ok"

sh exe_targetday.sh 20180506 20180507

检查文件数(check_file_num.sh)

#! /bin/sh
#
# check_file_num.sh
# Copyright (C) 2017 news_dl <news_dl@launcher-news-dl.hadoop.busdev.usw2.cmcm.com>
#
# Distributed under terms of the MIT license.
# ./check_file_num.sh s3://com.cmcm.instanews.usw2.prod/deeplearning/huangyanyan/trash/data/id_convert_path 20170309 20170322 102
 
targetPath=$1
startDay=$2
endDay=$3
fileNum=$4
while [ ${startDay} -le ${endDay} ]
do
  num=`hadoop fs -ls ${targetPath}/$startDay|wc -l`
  echo "startDay="$startDay",num="$num
  if [ "$num" -eq "$fileNum" ]
  then
    echo "ok"
  else
    echo "no"
    exit 1
  fi
  startDay=`date -d "${startDay} 1 day" +"%Y%m%d"`
done
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,513评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,312评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,124评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,529评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,937评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,913评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,084评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,816评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,593评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,788评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,267评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,601评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,265评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,158评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,953评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,066评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,852评论 2 277

推荐阅读更多精彩内容