linux-shell语法、例子(case)

13 篇文章 0 订阅

文章目录

一、COM

shell不算是高级语言,是面向过程的,但其目的本身就不是为了大型项目,而仅仅是以命令行的形式操作linux,其实就是多个linux命令的汇总,类似于宏。

Shell(外壳)跟kernel(内核)相互对应,意为跟内核交互的外层。
Shell本身是一个程序,它提供了一个与用户交互的环境。这个环境只有一个命令提示符,用于接收用户输入命令,再将命令提交给操作系统执行,最后将结果返回给用户,所以又称为命令行环境(commandline,CLI)。
Shell也是一个命令解释器,可以解释执行用户输入的命令(shell脚本)。

要理解shell,先要明确几个认知,

  1. 任何程序都不能直接操作计算机,这里的计算机是狭义的计算机硬件,只有kernel才能直接操作,而人显然不能去操作kernel,所以需要一个中介,这个中介就是shell,中介显然有很多种,比如java程序、python程序,shell也有很多种:bash、dash。

    1. 都说Shell可以直接与计算机交互,但是我想其他语言不也能方便的与计算机进行交互吗?
      不是shell可以和计算机交互,是用户通过shell与OS交互。其他语言编译完,就等待用户运行,可是怎么让OS知道用户要运行哪一个呢?参数是什么呢?这就需要shell了。从角色上看,windows系统的explorer程序也是一种shell,只不过是图形的,用户通过点击与OS完成交互。所以,shell的最重要的作用就是把用户的命令交给OS,和一般的计算机语言不在同一层。
  2. linux的命令其实都是函数,比如mkdir,就是用c写的一个函数

而Shell 的优势就是能轻易调用所有用其他语言编写的程序,比如可以在一个shell里调用用c写的mkdir,用java -jar调用java程序。当然java里面也可以调用mkdir,但显然需要多一些封装。

==》
shell,就是个命令行式的函数调用器。windows的各种图形化操作其实都是shell操作。shell可不仅仅是命令行。而是中介和桥梁。

二、命令提示符

[userName@hostname dir] $

username:指用户名
hostname:指主机名
dir:指当前目录,~表示用户主目录
KaTeX parse error: Expected 'EOF', got '#' at position 16: :用户提示符,root用户为`#̲`,非root用户为``
在这里插入图片描述

shell有很多有,比如bash和sh

切换shell

如果当前运行的不是bash,可以通过命令切换

# 当前登录使用的shell是sh,命令提示符为:sh-4.2$ 
# 通过bash命令即可切换shell为bashsh-4.2$
sh-4.2$ bash
[localadmin@server111 ~]$
[localadmin@server111 ~]$ sh
sh-4.2$
sh-4.2$
# 通过exit命令可以退出bash环境退回到sh环境。

三、命令组合符

1. 逻辑与(&&)

逻辑与(&&)的基本语法格式为:command1 && command2

其含义为:如果command1命令运行成功,则继续运行command2命令。如果command1命令运行失败,则不运行command2命令。

2. 逻辑或(||)

逻辑或(||)的基本语法格式为:command1 || command2

其含义为:如果command1命令运行失败,则继续运行command2命令。如果command1命令运行成功,则不运行command2命令。

3. 分号(;)

分号(;)的基本语法格式为:command1 ; command2

其含义为:command1命令执行完成后会执行command2命令。不管command1是否执行成功,都会执行command2。

四、syntax

1.解释器

!和/之间有没有空格都可

#!/bin/bash

2.须知

{1} 在sh中用ssh登录别的节点执行命令,别的节点反馈的控制台信息也会在执行sh的节点控制台打印出来

3.引号和括号

https://www.zhihu.com/search?type=content&q=shell%20%E5%BC%95%E5%8F%B7
https://zhuanlan.zhihu.com/p/64953183
在这里插入图片描述

[1] 双引号、单引号、反引号
[2] $ + 括号
[3] 括号、双括号

3.入参

标识符desc
$n$1 代表命令本身、$1-$9 代表第1到9个参数,10以上参数用花括号,如 ${10}。
$*命令行中所有参数,且把所有参数看成一个整体。
$@命令行中所有参数,且把每个参数区分对待。
$#所有参数个数。
$$当前进程的 PID 进程号。
$!后台运行的最后一个进程的 PID 进程号。
$?最后一次执行的命令的返回状态,0为执行正确,非0执行失败。

给shell传参

默认用空格分割,如果一个参数本身带有空格,可以用单、双引号 引起来,引号范围内的所有字符都认为是没有特殊含义的文本。如果不在引号范围内,可以用\表示转义

"etl_date = '202001' AND khh = '123' "
etl_date = \'202001\'

4.变量

系统变量

shell中的系统变量

变量含义
$0当前脚本的文件名。
$n(n≥1)传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是 $1,第二个参数是 $2。
$#传递给脚本或函数的参数个数。
$*传递给脚本或函数的所有参数。
$@传递给脚本或函数的所有参数。当被双引号" "包含时,$@ 与 $* 稍有不同,我们将在《Shell ∗ 和 *和 @的区别》一节中详细讲解。
$?上个命令的退出状态,或函数的返回值,我们将在《Shell $?》一节中详细讲解。
$$当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。

{1} 定义变量:变量名=变量值,注意等号两边不要有空格,否则会把空格也作为名字的一部分,一定要紧凑

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

{2} 使用变量:$变量名

{3} usage

[1] 将命令的返回值赋给变量

A=`ls` 反引号,执行里面的命令
A=$(ls) 等价于反引号

[2] 环境变量

/etc/profile只在系统启动时自动执行,所以修改之后需要手动source

5. 运算符

shell默认全部都是文本,想要计算表达式,需要放在特殊的标识中,需要设置运算符。
在 Shell 编程中有各种运算操作,语法格式为 $((运算式)) 或 $[运算式] 或者 expr m + n;如果希望将 expr 的值赋给某个变量,放在 `` 即可。
3种方式:

{1} $((运算式))

echo $(((2+3)*4))

{2} $[运算式],这里的中括号不是条件判断,跟if不同,前后不需要空格

echo $[(2+3)*4]

{3} 使用 expr

expr m + n 注意 expr 运算符间要有空格expr m - n

result3=`expr 2 + 3`
result4=`expr $result3 \* 4`
echo "expr res4=$result4"

*,/,% 分别代表乘,除,取余。乘号*在``中需要转义,但如果在上面2种中,不需要转
TEMP=`expr 2 + 3`
echo `expr $TEMP * 4`

6.流程控制

{1} 选择

https://blog.csdn.net/star_kite/article/details/124934333

[1]条件判断表达式
  • 条件判断使用语法 [ condition ](注意 condition 前后有空格),非空会返回 true。可以使用 $? 验证结果,0 为 true,>1 为false
  • [ hspEdu ] 会返回 true
  • [ ] 会返回 false
  • [ condition ] && echo yes || echo no ,前一个判断满足时会继续执行后面的语句
if [ $a == $b ]
then
   echo "a is equal to b"
elif [ $a -gt $b ]
then
   echo "a is greater than b"
elif [ $a -lt $b ]
then
   echo "a is less than b"
else
   echo "None of the condition met"
fi
[2]条件判断分类,字符串、数值、文件

{2} 循环

shell中的循环有2种形式for(())和for i in x x x,x x x可以不带引号,可以直接用变量,比如\$1、\$*
https://www.cnblogs.com/EasonJim/p/8315939.html

for i in {1..5}
do
    echo $i
done


for i in 5 6 7 8 9 #是空格不是逗号
do
    echo $i
done

#循环数组${arr[@]} 不能用$arr,这样只有第一个元素
#"${arr[@]}" 要用双引号包裹,避免数组中元素出现莫名其妙的切分
#定义数组间隔空格,字符串需要加双引号
#shell中的空格要用空格,不能用tab
arr=("13-2020年年度个人总结" "14-2021年年度个人总结" "15-2020和2021年绩效考核结果及说明" "16-2020年绩效考核办法" "17-2021年绩效考核办法")
for i in "${arr[@]}"; do
  echo $i"(无).pdf"
done


for((host=105;host < 108;host++));
do
    ssh node$host /opt/cm-5.16.2/etc/init.d/cloudera-scm-agent $1
done


for FILE in $HOME/.bash*
do
   echo $FILE
done
break  #跳出所有循环
break n  #跳出第n层f循环
continue  #跳出当前循环
COUNTER=0
while [ $COUNTER -lt 5 ]
do
    COUNTER=`expr $COUNTER + 1`
    echo $COUNTER
done

{3} switch

case $变量名 in
"值 1")
;;
如果变量的值等于值1,则执行程序1,值
"值 2")
如果变量的值等于值2,则执行程序2
…省略其他分支…
;;
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac

7.函数

shell中定义函数有3种方式,这3种方式等价

		f_name(){……}
		function f_name{……}
		function f_name(){……}

传参,注意定义时的括号里面不需要形参,在函数体中通过$num直接用即可。注意,函数中的\$num和脚本的\$num不同

test(){
    echo $1  #接收第一个参数
    echo $2  #接收第二个参数
    echo $3  #接收第三个参数
    echo $#  #接收到参数的个数
    echo $*  #接收到的所有参数
}

test aa bb cc

如果这个函数想要在脚本之外用,EXPORT 函数名

调用时,直接函数名 arg1 arg2

8.重定向

linux也有流的概念,有流就有源和目的地,目的地有很多种,可以换。这个换就是重定向。既然是写,也就有append和overwrite的区别。
1是标准输出,其实就是日志
2是错误,报错时的输出,相当于System.err

$echo result > file  #将结果写入文件,结果不会在控制台展示,而是在文件中,覆盖写
$echo result >> file  #将结果写入文件,结果不会在控制台展示,而是在文件中,追加写

9.EOF

在shell脚本中,通常将EOF与 << 结合使用,表示后续的输入作为子命令或子Shell的输入,直到遇到EOF为止,再返回到主Shell。
EOF只是一个分界符,当然也可以用abcde替换。
当shell遇到<<时,它知道下一个词是一个分界符。在该分界符以后的内容都被当作输入,直到shell又看到该分界符(位于单独的一行)。
此分界符可以是所定义的任何字符串,其实,不一定要用EOF,只要是“内容段”中没有出现的字符串,都可以用来替代EOF,完全可以换成abcde之类的字符串,只是一个起始和结束的标志罢了。

syntax

<<EOF xxx EOF
EOF中的内容不需要加分号,换行分隔即可

notice

  • 1.结束的EOF后面不要带分号,并且2个EOF之间的部分前面不要有tab和空格。否则会语法错。下图的是正确的:
    在这里插入图片描述

非阻塞、后台执行

在命令最后加&表示后台运行,但即使后台运行,日志也会打印到console,此时需要>/dev/null 2>&1。但此时的后台运行仅在当前终端有效,如果当前账户退出???,程序仍会停止,此时就需要nohup。

须知:

>/dev/null 2>&1

> 表示重定向
/dev/null代表空设备文件,又叫黑洞,也就是不输出任何信息到终端
1 表示stdout 标准输出,系统默认值是 1
所以 > /dev/null 相当于 1 > /dev/null
2 表示 stderr 标准错误
即 >/dev/null 2>&1 含义即是将 标准输出、标准错误重定向至空设备文件

nohup 不挂断的运行

no hang up
忽略挂起信号的情况下运行给定的命令,以便注销后命令可以在后台继续运行。
一般情况 nohup ./test & ,此时会默认把日志输出到当前路径下的nohup.out文件中,如果不想要,可以
nohup ./test > myout.txt 2>&1 &nohup ./test >/dev/null 2>&1 &

& 后台运行

example

提交spark任务时,需要使用命令调用脚本,而spark-submit默认是在前台阻塞的,脚本执行后都会开1个进程。阻塞的意思就是这个脚本执行后,这个进程会一直在,直到脚本中的程序执行完。
ps aux
此时可以在脚本的命令中设置nohup 和 &来非阻塞执行。

case

1.CDH启停

#! /bin/bash

#1 判断参数个数,如无参数输入,直接退出
argscount=$#
if((argscount == 0));
then
    echo ============================no args============================
    exit;
fi

#2 函数封装
function start(){
    echo ============================启动CDH:begin============================

    #   判断mysql是否启动,如果没启动,先启动mysql
    mysqlPortStat=`netstat -anp | grep 3306 | wc -l`
    if [ $mysqlPortStat == 0 ]
    then
        ssh node105 systemctl start mysqld
    fi
    echo "mysql 已经启动"

    #   启动CDH
    sleep 1s;

    ssh node105 /opt/cm-5.16.2/etc/init.d/cloudera-scm-server $1

    for((host=105;host < 108;host++));
    do
        ssh node$host /opt/cm-5.16.2/etc/init.d/cloudera-scm-agent $1
    done
    # 获取当前前后时间的从1970UTC为止的秒数
    start_datetime=`date +%s`
    # CDH启动最起码需要等待30s,所以先sleep 30s; 然后再轮循
    sleep 30s;

    #   监控7180端口,如果监听到数量大于0,说明CDH启动完成
    CDHPortCount=`netstat -anp | grep 7180 | wc -l`
    while [ $CDHPortCount == 0 ]
    do
        CDHPortCount=`netstat -anp | grep 7180 | wc -l`
        sleep 5s;
    done

    end_datetime=`date +%s`
    echo $end_datetime

    echo ============================启动CDH:successed,等待$[end_datetime-start_datetime]s============================
}

function stop(){
    echo ============================停止CDH:begin============================
    for((host=105;host < 108;host++));do
        ssh node$host /opt/cm-5.16.2/etc/init.d/cloudera-scm-agent $1
    done

    ssh node105 /opt/cm-5.16.2/etc/init.d/cloudera-scm-server $1
    echo ============================停止CDH:successed============================
}

function restart(){
    # 判断mysql是否启动,如果没启动,先启动mysql
    mysqlPortStat=`netstat -anp | grep 3306 | wc -l`
    if [ $mysqlPortStat == 0 ]
    then
        ssh node105 systemctl start mysqld
    fi
    echo "mysql 已经启动"
    #
    echo ============================重启CDH:begin============================
    for((host=105;host < 108;host++));
    do
        ssh node$host /opt/cm-5.16.2/etc/init.d/cloudera-scm-agent $1
    done

    ssh node105 /opt/cm-5.16.2/etc/init.d/cloudera-scm-server $1
    echo ============================重启CDH:successed============================
}

#3 根据输入参数执行相应操作
case $1 in
    "start")
        start $1;
    ;;
    "stop")
        stop $1;
    ;;
    "restart")
        restart $1;
    ;;
esac

2.rrsync分发脚本

#!/bin/bash
#1 获取输入参数个数,如果没有参数,直接退出
pcount=$#
if((pcount==0)); then
echo no args;
exit;
fi

#2 获取文件名称
p1=$1
fname=`basename $p1`
echo fname=$fname

#3 获取上级目录到绝对路径
pdir=`cd -P $(dirname $p1); pwd`
echo pdir=$pdir

#4 获取当前用户名称
user=`whoami`

#5 循环
for((host=105; host<108; host++)); do
	echo ------------------- node$host --------------
	rsync -rvl $pdir/$fname $user@node$host:$pdir
done

3.xcall统一执行脚本

#! /bin/bash

for i in node105 node106 node107
do
	echo --------- $i ----------
	ssh $i "$*"
done

4.递归目录下所有文件,并替换

在当前目录下,查找最近2天的sh文件,然后把里面的'/*/*'替换为'/*/*/*'

find . -type f -name '*.sh' -ctime -2 | xargs sed -i 's/\/\*\/\*/\/\*\/\*\/\*/g' 

5.递归执行目录下的所有sh脚本

递归执行当前目录下所有sh脚本,注意:
最后的\不能省,因为会被认为一行没结束,所以后面加分号;

find . -maxdepth 1 -name '*.sh' -exec {} \;
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值