shell语言学习(更新中)

1、概念

Shell是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务, Shell脚本(shell script),是一种为Shell编写的脚本程序。我们经常说的shell通常都是指shell脚本。

2、脚本输出方法

a、echo [选项] [内容]

 当选项为 -e的时候,内容里面出现以上的内容时,就会识别上表中的符号

如 echo -e 'hello' => 输出 helo

echo输出颜色表示:echo  -e  "e[1;31mthis is test e[0m"

#30m: 黑色   #31m:红色    #32m:绿色    #33m:黄色     #34m:蓝色     #35m:洋红       #36m:青色    #37m:白色

3、脚本的声明

#!/bin/bash    //可以用echo $SHELL进行查看
echo 'hello world!'

说明:

  • #! 告诉系统这个脚本需要什么解释器来执行。
  • 文件扩展名 .sh 不是强制要求的。
  • 方法1 直接运行解释器,hello.sh 作为 Shell 解释器的参数。此时 Shell 脚本就不需要指定解释器信息,第一行可以去掉。
  • 方法2 hello.sh 作为可执行程序运行,Shell 脚本第一行一定要指定解释器。

注意:在shell中常常会看到exit 0 这里的0表示成功退出非0表求错误退出。

4、脚本的运行

// 方法1
sh hello.sh

// 方法2
chmod +x hello.sh
./hello.sh

// 方法3
sh hello.sh

5、shell变量

定义:Shell 变量分为系统变量和自定义变量。系统变量有$HOME、$PWD、$USER等,显示当前 Shell 中所有变量:set 。

变量名可以由字母、数字、下划线组成,不能以数字开头。

#!/bin/bash
name='testName'  //注意:这里是不能有空格的
readonly name      //一旦声明了readonly,那么这个为师是只读的,不允许更改
//使用变量 
echo $name
//或者
echo ${name}

删除变量

#!/bin/bash
name='aaa';
readonly name;
age=20;
unset name;   //readonly 的变量是不能被删除
unset age;      //可以被删除

注意:变量的定义与变量的删除都不用$符来修饰

通常上面定义的是全局变量,不建议定义全局变量,可以使用局部变量,在变量前面添加local 关键字

# 定义局部变量
function test2(){
  local -i a=3      //如果declare与local并在的时候,写法可以省去declare
  declare -i b=3
}

 6、shell字符串

 双引号的字符串拼接

#!/bin/bash
name='bill';
age=20;
echo -e "e[1;34m 我的名字叫"${name}"我今年"$age"岁了e[0m";
echo -e "e[1;35m 我的名字叫${name},我今年${age}岁了e[0m";

双引号可以解析引号内的内容

your_name='runoob'
str="Hello, I know you are "$your_name"! 
"
echo -e $str

单引号的字符串拼接

# 使用单引号拼接
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name} !'
echo $greeting_2  $greeting_3

获取字符串的长度

#!/bin/bash
name="are you ok   ???";
echo "name的长度是:${#name}";
echo "name的长度是"`expr length "$name"`;

提取查询的子串的长度

echo `expr match "$name" today`  //输出5
echo `expr match $name good` //输出0

注意:这里是需要从第一位开始匹配的

提取子字符串

注意:第三个方法的负数最好有一个空格,或者采用第四种方法,表示的是从左边截取几位数

#!/bin/bash
str="bill is super man!";
echo "第二个字符到第六个字符是${str:2:6}";
#输出 第二个字符到第六个字符是ll is
echo ${str: -3}  //输出 an! 注意中间需要有一个空格
string="abcdefghijklmnopqrstuvwxyz";
echo ${str: -12:3}  //输出opq  注意从右边开始算,取正常顺序的3个字符

查找子字符串

查找是从第1位开始,如果没有找到那么就返回0,例如查找ac是先查找a然后再查找c,看哪个先找到,那么就返回先找到的部份,当a与c都能找到的情况下,返回比较小的值

#!/bin/bash
str="abcdefghijklmnopqrstuvwxyz";
echo `expr index "$str" s`;
echo `expr index "$str" ac`;

注意: 以上脚本中 ` 是反引号,而不是单引号 ',不要看错了哦。

变量替换

 举例:

#!/bin/bash
str="I see a yellow duck looking at me";
clip1=${str#*a};
clip2=${str##*a};
echo $clip1;                //输出 yellow duck looking at me
echo $clip2;                //输出 t me
clip3=${str%a*};
clip4=${str%%a*};
echo $clip3;               //输出 I see a yellow duck looking
echo $clip4;               //输出 I see
clip5=${str/a/bb};
clip6=${str//a/bb};
echo $clip5;               //输出 I see bb yellow duck looking at me
echo $clip6;               //输出 I see bb yellow duck looking bbt me

文本练习

#!/bin/bash
str="Bigdata process framework is Hadoop, Hadoop is an open source project";

function show_tip() {
  echo "*******************************";
  echo "(1)打印string的长度";
  echo "(2)删除字符串中所有的Hadoop";
  echo "(3)替换第一个Hadoop为Mapreduce";
  echo "(4)替换全部Hadoop为Mapreduce";
  echo "*******************************"
}

function show_len() {
  echo "string的长度是${#str}";
}

function del_str() {
  echo ${str//Hadoop};
}

function rep_str() {
  echo ${str/Hadoop/Mapreduce};
}

function rep_all_str() {
  echo ${str//Hadoop/Mapreduce};
}


while true;
do
  echo "【str=$str】";
  show_tip;
  read -p "请选择对应的操作1|2|3|4|q|Q: " choice
  case $choice in
    1) show_len;;
    2) del_str;;
    3) rep_str;;
    4) rep_all_str;;
   q|Q) exit;;
    *) echo "输入有误,请重新输入(1|2|3|4|q|Q)";
  esac
done

7、数组

bash支持一维数组(不支持多维数组),并且没有限定数组的大小。

类似于 C 语言,数组元素的下标由 0 开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于 0。

数组的定义

数组名=(值1 值2 ... 值n)

也可以采用各个项来定义

array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen

输出数组

#!/bin/bash
arr=("a" "b" "c" "d");
echo ${arr[0]};        //输出第0项
echo ${arr[@]};        //输出所有项数组          

输出数组的长度

#!/bin/bash
arr=("aa" "bbb" "cccc" "ddddd");
echo "数组的长度是"${#arr[@]};              //输出4
echo "这个也是数组的长度"${#arr[*]};         //输出4
echo "这个是数组中单项的长度"${#arr[3]};      //输出5   

8、函数的定义

函数的定义方式:

$n表示输出第n位参数,$@与$*的意思一样表示输出所有的参数,$#表示参数的个数

#!/bin/bash
function func() {
  echo $1,$@;
}
func "gaga";

 练习:

#!/bin/bash

function count {
  case $2 in
    +) echo `expr $1 + $3`;;
    -) echo `expr $1 - $3`;;
    *) echo `expr $1 * $3`;;
    /) echo `expr $1 / $3`;;
  esac
}

count $1 $2 $3


//调用的时候  sh bash.sh 12 + 2

函数的返回值

 return 返回值 只能返回1-255的整数。通常return只是用来供其他地方调用获取状态,因此通常仅返回0或1;0表示成功,1表示失败

 echo 返回值可以返回任何字符串结果 。通常echo用于返回数据,比如一个字符串值或者列表值。

#!/bin/bash

function getUser {
  user=$(cat /etc/passwd|cut -d ":" -f 1);
  echo $user;       //返回值是查询结果
}

data=`getUser`;

for var in $data;
do
  echo $var;
done;
exit;
 

9、shell中的read命令

简单读取

#!/bin/bash
echo "请输入任意的内容";
read content;                        //把输入的内容赋值给content这个变量
echo "你输入的内容是"$content;
  • -p 后面跟提示信息,即在输入前打印提示信息。
  • -t 后面跟秒数,定义输入字符的等待时间。
  • -s 安静模式,在输入字符时不再屏幕上显示,例如login时输入密码。
  • -n 后跟一个数字,定义输入文本的长度,很实用。
#!/bin/bash
read -p "请输入任意的内容:" content;
echo "你输入的内容是:"$content;
#!/bin/bash
if read -t 5 -p "请5秒内输入用户名:" user;    //这里在-t后面跟数据可以有空格,也可以没有空格
then
  echo "您输入的用户名是:"$user;
else
  echo "对不起,你输入超时";
fi
exit 0;
#!/bin/bash
read -n1 -p "请选择Y|N" sign          //这里的-n后面跟数据可以有空格,也可以没有空格
echo "你输入的是:"$sign;

 10、字符串的运算符

使用[[ ... ]]条件判断结构,而不是[ ... ],能够防止脚本中的许多逻辑错误。比如,&&、||、<和> 操作符能够正常存在于[[ ]]条件判断结构中,但是如果出现在[ ]结构中的话,会报错。比如可以直接使用if [[ $a != 1 && $a != 2 ]], 如果不适用双括号, 则为if [ $a -ne 1] && [ $a != 2 ]或者if [ $a -ne 1 -a $a != 2 ]。

#!/bin/bash
read -n1 -p "请输入对应的指令Y|N" sign;
if [[ $sign = "Y" || $sign = "y" ]]            //这里的[[]]的前后都要加上空格,在if后面也要加上空格
then
  echo "你输入的是肯定的回答";
elif [[ $sign = "N" || $sign = "n" ]]
then
  echo "你输入的是否定的回答";
else
  echo "输入的字符不合法,请输入Y|N";
fi
exit 0;

11、流程控制语句

if...elif...else例子如上

case 语句,相当其他语法的switch

#!/bin/bash
num=12;
case $num in
  1|2|3|4|5|6|7|8|9) echo '这个值是小于10的值';;
  10) echo "这个值是等于10的值";;
  *) echo "这个值是大于10的值";;
esac
exit 0;

for语名的使用

#!/bin/bash
for((i=0; i<=10; i++)); do
echo "现在输出的是"${i};
done;
exit 0;

注意:这里使用的是双括号

#!/bin/bash
arr=("aa" "bb" "cc" "dd" "ee");
for per in ${arr[@]};
do
  echo "值为"$per;
done

exit 0;

while的使用

#!/bin/bash
int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"
done

注意:这里的Let相当于(())的用法

12、命令替换

#!/bin/bash
echo $(date +%Y);
echo `date +%Y`;
echo "明年是"$((`date +%Y` + 1))"";
echo "明年是"$(($(date +%Y) + 1))"";

如果没有命令替换,那么会输出命令

#!/bin/bash
//当本机的ngnix进程没有的时候,那么重新启动nginx服务
nginx_process_num = $(ps -ef | grep nginx | grep -v grep | wc-1)   //重点表示过滤
if [ $nginx_process_num -eq 0 ];
then
  systemctl start nginx
fi

 13、cut的使用

常用命令  cut  -d  ":"  -f  1  表示从字符串中截取一部份 -d:表示自定义分隔符,默认为制表符,“:” 表示以:进行分割, -f:与-d一起使用,指定显示哪个区域。1:表示取第一部份

#!/bin/bash
name="this is test are you ok???";
echo $name|cut -d " " -f 1;    //输出 this

 14、wc的使用

在默认的情况下,wc将计算指定文件的行数、字数,以及字节数。使用的命令为:

wc testfile

  • -l或--lines 只显示行数。
  • -w或--words 只显示字数。
wc test.sh   //输出  6 11 72 bash.sh
ls -l|wc -l    //输出 3  表示有3条记录

 15、bc的使用

bc 命令是任意精度计算器语言,通常在linux下当计算器用。一般来讲,等式的小数位数决定了答案的位数

#!/bin/bash
echo "scale=2;3/8" | bc;       //输出 0.37
echo "0.356 * 2" | bc;          //输出0.712
        

 

向上取整与向下取整的函数封装

parseFloat() {
    echo "$1 + 0.000" | bc
}

floor() {
    a=$(parseFloat $1)
    b=$(parseFloat $2)
    echo `echo "scale=0; $a/$b" | bc`
}

ceil() {
    a=$(parseFloat $1)
    b=$(parseFloat $2)
    num=$(echo "scale=2; $a/$b" | bc)
    int=$(floor $a $b)

    if [ $(echo "$int < $num"|bc) -eq 1 ];
    then
        echo $(($int+1))
    else
        echo $int;
    fi
}

round() {
    a=$(parseFloat $1)
    b=$(parseFloat $2)
    num=$(echo "scale=2; $a/$b" | bc)
    int=$(floor $a $b)
    middle=$(echo "$int + 0.5" | bc)

    if [ $(echo "$middle < $num"|bc) -eq 1 ];
    then
        echo $(($int+1))
    else
        echo $int;
    fi
}

echo $(floor 11 3) 3
echo $(floor 12 3) 4
echo $(floor 13 3) 4
echo $(floor 14 3) 4
echo $(ceil 11 3) 4
echo $(ceil 12 3) 4
echo $(ceil 13 3) 5
echo $(ceil 14 3) 5
echo $(round 11 3) 4
echo $(round 12 3) 4
echo $(round 13 3) 4
echo $(round 14 3.3) 4
echo $(round 15 3) 5

 16、ps的用法

ps命令 用于报告当前系统的进程状态。可以搭配kill指令随时中断、删除不必要的程序。ps命令是最基本同时也是非常强大的进程查看命令,使用该命令可以确定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等等,总之大部分信息都是可以通过执行该命令得到的。

以下是ps的常用用法

ps axo pid,comm,pcpu # 查看进程的PID、名称以及CPU 占用率
ps aux | sort -rnk 4 # 按内存资源的使用量对进程进行排序
ps aux | sort -nk 3  # 按 CPU 资源的使用量对进程进行排序
ps -A # 显示所有进程信息
ps -u root # 显示指定用户信息
ps -efL # 查看线程数
ps -e -o "%C : %p :%z : %a"|sort -k5 -nr # 查看进程并按内存使用大小排列
ps -ef # 显示所有进程信息,连同命令行
ps -ef | grep ssh # ps 与grep 常用组合用法,查找特定进程
ps -C nginx # 通过名字或命令搜索进程
ps aux --sort=-pcpu,+pmem # CPU或者内存进行排序,-降序,+升序
ps -f --forest -C nginx # 用树的风格显示进程的层次关系
ps -o pid,uname,comm -C nginx # 显示一个父进程的子进程
ps -e -o pid,uname=USERNAME,pcpu=CPU_USAGE,pmem,comm # 重定义标签
ps -e -o pid,comm,etime # 显示进程运行的时间
ps -aux | grep named # 查看named进程详细信息
ps -o command -p 91730 | sed -n 2p # 通过进程id获取服务名称

例如查找linux中nginx的进程 ps -ef| grep nginx | grep -v grep

17、有类型的变量(即类型声明)

在shell中进行变量类型声明,需要通过declare和typeset两个命令进行操作,这两者是等价的, 下在以declare为例:

 注意:声明了环境变量后,在脚本中就可以直接使用

 取消声明的变量

取消声明的变量
declare +r  取消只读
declare +i  取消只为整型
declare +a  取消只为数组
declare +x  取消只为环境变量

 18、bash数学运算之expr

语法:

 注意:expr后面每个单语需要有空格,operator表示运算符

 

注意:在expr运算中,特殊的符号需要加上转义符号

#!/bin/bash
num1=100;
num2=200;
num3=$(expr $num1 + $num2);  //使用这种语法,在赋值的时候需要进行转义
num4=`expr $num2 + $num3`;
num5=$(($num3 + $num4));
echo $num3;
echo $num4;
echo $num5;

 注意:$(())不是一个表达式,但是可以进行赋值, expr是一个表达式,命令,可以单独运行,所以在expr进行赋值的时候,需要进行命令的替换。

 练习:

[root@instance-yvmni62c ~]# cat bash.sh
#!/bin/bash

info() {
  echo "********************************************";
  echo "输入一个数求和";
  echo "********************************************";
}

isInt() {
  num=$(echo "scale=0; $1/1"|bc);
  echo `expr $num >= $1`;
}

getTotal() {
  num=0;
  for((i=0; i<=$1; i++)); 
  do
    num=$(($num + $i));
  done

  echo "总和是"$num;
}


while true
do
  info;
  read -p "请输入一个数:" count;
  echo $count;
  if [ $count -gt 0 ] && [ $(isInt $count) -eq 1 ]
  then 
   getTotal $count;
  else 
    echo "输入的数字格式有误";
  fi
done

 判断是否是正整数

#!/bin/bash
read -p "输入一个数 " count;
expr $count  + 1 &> /dev/null;
echo $?;    //输出0表是是正整数  1是负数  2是小数

 19、sleep表示睡眠

sleep(参数)

#!/bin/bash

b=''
for ((i=0;$i<=100;i++))
 do
 printf "Progress:[%-100s]%d%%
" $b $i
 sleep 0.1
 b=#$b
 done
echo

 20、find的使用细节

 常用选项配置

find命令总结
常用选项:
-name          查找/etc目录下以conf结尾的文件 find /etc -name '*conf'
-iname         查找当前目录下文件名为aa的文件,不区分大小写 find . - iname aa
-user          查找文件属主为hdfs的所有文件 find . -user hdfs
-group         查找文件属组为yarn的所有文件 find,- group yarn
-type
         f           文件                            find . -type f
         d           目录                            find . -type d
         c           字符设备文件                     find . -type c
         b           块设备文件                       find . -type b
         l           链接文件                        find . -type l
         p           管道文件                        find . -type p
-size
        -n           大小大于n的文件
        +n           大小小于n的文件
        n            大小等于n的文件
例子1:查找/etc目录下小于10000字节的文件   find /etc -size -10000c
例子2:查找/etc目录下大于1M的文件   find /etc -size +1M
-mtime
       -n            n天以内修改的文件
       +n            n天以外修改的文件
       n             正好n天修改的文件
例子1:查找/etc目录下5天之内修改且以con结尾的文件 find /etc -mtime -5 -name '*.conf'
例子2:查找/etc目录下10天之前修改且属主为xoot的文件 find/etc -mtime +10 -user root

 对查找到的结果进行操作

语法  find【路径】【选项】【操作】-exec command {} ;

例子:

 

 练习:

#!/bin/bash

if [ ! -d 'abc' ];
then
  echo "文件夹不存在的哈";
  exit;
fi

function dealFile {
  cd ~;
  mkdir -p 'bf/conf';
  mkdir -p 'bf/sh';
  cd "abc";
  find ./ -name "*.conf" -exec mv {} ../bf/conf/ ;
  wait $!      #等待上个命令执行完成
  find ./ -name "*.sh" -exec mv {} ../bf/sh ;
  wait $!;
  cd ~;  
  rm -rf abc;
  mv bf abc;
  cd abc;
}

#对所对应的两个文件夹进行压缩处理,conf采用bz2压缩,sh采用gz压缩

function packFile {
  tar -jcvf conf.tar.bz2 ./conf
  tar -zcvf sh.tar.gz ./sh
  #删除原有的目录
  rm -rf conf sh;
}

 21、grep与egrep的使用

grep: 是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。用于过滤/搜索的特定字符。可使用正则表达式能多种命令配合使用,使用上十分灵活。

egrep: 用于在文件内查找指定的字符串。egrep执行效果与grep -E相似,使用的语法及参数可参照grep指令,与grep的不同点在于解读字符串的方法。

 grep的语法格式:

 ◆第一种形式:   grep [option] [ pattern] [file1,file2...]   这种形式主要是在文件中查找,遍历文件的每一行,如果有匹配的就把那行列出来;

 ◆第二种形式:  command | grep [option][pattern]  这种形式主要是在命令的终端中进行查找 

grep常用的配置选项

 grep -r ~/   表示在~目录下对所有文件进行递归查询,在普通文件下是没有意义的。

 

 22、rpm的使用

rpm命令 是RPM软件包的管理工具。在查询nginx的时候可以使用 rpm -ql nginx来查询相应的信息

 23、sed的工作模式

sed:流编辑器。对标准输出或文件逐行进行处理

sed的语法格式:

  ◆第一种形式: stdout | sed  [option]  "pattern command"

  ◆第二种形式:sed [option] "pattern command" file

sed的选项

sed 'p' test.txt  //这里的p是个命令表示print的意思 , 原来sed有打印的意思,所以这里会输出2次
sed -n 'p' test.txt  // -n表求静默模式,会取消原来默认的打印模式,所以只会打印一次
sed -n '/day/p' test.txt // 这里的day表示查询匹配的意思,后面的p表示print(以行为单位进行匹配),也可以是day.*表示匹配day后面有的所有字符

 -e可以理解成或的关系,如果有有一个可以不写,但是有多个就都要写

sed -n -e  '/day/p'  -e '/ok/p' test.txt   //表示输出含day,也输出含有ok的行

-f可以理解为file,例如新建一个文件key.txt里面的内容是 /ok/p

sed -n -f key.txt test.txt   //表示把key.txt中的内容拿到test.txt中进行匹配

 -r表示正则表达式

sed -n -r '/ok|day/p' test.txt

-i表示修改文件内容

sed -n -i 's/day/today/g;p' test.txt   //表示把文中的day 改成today;p表示输出(可省),如果没有-i那么只是把改的结果输出给你,原文不更改,加-i后会更改原文件

 set中的pattern祥解表示匹配模式

30、$()与${}, $(()), []的区别

shell中要对一个命令的结果做操作这时候就要用到$(),但是如果只对一个变量做操作的时候就要用到${}

$(())是用来作整数运算的。在bash中, $(())的整数运算符号大致有这些:

  • +- * / #分别为”加、减、乘、除”。
  • % #余数运算,(模数运算)
  • & | ^ ! #分别为”AND、OR、XOR、NOT”运算。

[ ] :即为test命令的另一种形式。

但要注意许多:

1.你必须在左括号的右侧和右括号的左侧各加一个空格,否则会报错。

2.test命令使用标准的数学比较符号来表示字符串的比较,而用文本符号来表示数值的比较。很多人会记反了。使用反了,shell可能得不到正确的结果。

#!/bin/bash
str="this is text";
#使用变量
echo "这是一个测试文本"${str};
#使用一个命令的结果做操作
for var in $(cat /etc/passwd|cut -d ":" -f 1)
do
  echo $var;
done

 if语句中用[]来判定,常用等式中用$(())来获取结果

原文地址:https://www.cnblogs.com/rickyctbu/p/12166039.html