shell

shell

查看本地支持的shell

cat/etc/shells

/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/bin/dash
/usr/bin/dash

查看本地默认shell

ls -l /bin/ |grep bash


-rwxr-xr-x 1 root root     1183448 4月  18 17:14 bash
-rwxr-xr-x 1 root root        6794 4月  18 17:14 bashbug
-rwxr-xr-x 1 root root        2446 1月  26  2020 dh_bash-completion
lrwxrwxrwx 1 root root           4 4月  18 17:14 rbash -> bash
rbash 是乌班图默认的

格式开头

#!/bin/bash

第一个脚本

#!/bin/bash
echo "hello word"

脚本常见的执行方式

1.直接使用bash执行

bash  hello.sh

2.全路径bash

bash /home/player3/shells/hello.sh


sh /home/player3/shells/hello.sh

3.相对路径

./hello.sh
bash: ./hello.sh: 权限不够
需要给脚本增加权限
chmod +x hello.sh

4.使用点命令

. hello.sh

5.使用source命令

source  hello.sh

前面3种都是使用了子bash进程来执行,后两种是逐行执行当前的脚本

变量

系统预定义变量

$HOME ,$PWD,$SHELL,$USER等等

显示当前shell中所有变量:set

set  
会显示所有变量 x=xxx的形式

全局的环境变量

子shell也有效

echo $HOME
查看环境变量的值

查看所有的全局环境变量
env 
printenv

局部的环境变量

只在当前shell有效

自定义变量

1.变量名可以由字母,数字,下划线组成,但是不能以数字开头,环境变量名建议大写

2.等号两侧不能有空格

3.在bash中,变量默认类型都是字符串类型,无法直接进行数值运算

4.变量的值如果有空格,需要使用双引号,或单引号括起来

定义局部变量

命令行输入 my_var=‘hello word’

echo $my_var

但是这是全局的还是局部的呢

看全局的: env |grep my_var
看所有的环境变量:set |grep my_var
在所有的环境变量中查到了这个值,所以这个环境变量是局部的

导出到全局变量

export my_var

子shell修改不会改变现有全局变量的数据

变量的数据类型

变量的数据类型初始并没有定义或者默认字符串

数值运算

a=$((1+5))

a=$[5+9]


命令行的操作:expr 1 + 2

乘法的时候需要注意:expr 1 \* 2
为了更加简便 $((运算式))或$[运算式]

计算两个数的和

sum=$[$1+$2]
echo sum=$sum

只读变量

readonly b=5
b=10

bash:b:只读变量

撤销变量

unset a

特殊变量

$n
n为0-9,0为脚本的名称,1-9代表第一到第九的参数,9以上需要${10}

sh文件中单引号会把¥原封不动的显示出来

test测试:

hello.sh文件

#!/bin/bash
echo '-------$n---------'
echo name:$0
echo get:$1
echo get $2             

执行后:./hello.sh liming wangwu

./hello.sh  liming wangwu
-------$n---------
name:./hello.sh
get:liming
get wangwu

如何把脚本名称显示正常?

echo name:$(basename $0)

获取所有输入参数个数

功能描述,获取所有输入参数个数,用于循环,判断个数是否正确以及加强脚本健壮性

$#
所有参数,每个参数区分对待
命令:
liming wangwu

最后一次执行的命令的返回状态

#? 在最后一次执行的命令的返回状态,这个变量的值如果为0,证明上一个命令正确,如果这个变量的值非0(具体哪个数,由命令来决定),则证明上一个命令执行不正确了

sh文件直接执行的方案

直接放在bin目录和sbin目录

最好不要直接复制到这些目录

PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin 

可以丢到这些目录下或者配置环境变量

条件判断

test 条件非空为true,正确为true,否则为false

常用
-eq 等于  -ne 不等于
-lt 小于 -le小于等于
-gt 大于  -ge大于等于
如果是字符串比较==判断相等,!=判断不等于
按照文件权限进行判断
-r 有读的权限
-w 有写的权限
-x 有执行的权限
按照文件类型进行判断:
-e 文件存在
-f 文件存在并是一个常规的文件
-d 文件存在并且是一个目录

test 1=1
#?
1.

案例

1.23是否大于等于22

[23 -ge 22]
echo $?

2.helloword.sh是否有读写权限

[- w helloworld.sh]
echo $?

3./home/at.txt目录文件是否存在

[-e /home/at.txt]
echo $?

if判断

单分支:
if[条件判断式];then
程序
fi
------------------------------
或者
if[条件判断式];
then
程序
fi
--------------------------
多分支
if[条件判断式];
then
程序
elif [条件判断式];
then
程序
else
程序
fi

1.[条件判断式] 中括号和条件表达式之间必须有空格
2.if后有空格

case判断

case $变量名 in 
“值1”)
结果
;;
“值2”)
结果
;;
*)
esac
注意事项:
1.case 行尾必须单词 in ,每个模式匹配必须右括号)结束
2.双分号;;表示命令序列结束,相当于java的break
最后的*)表示默认模式,相当于default

案例

case $1 in
        1)
                echo 'one'
                ;;
        2)
                echo 'two'
                ;;
        *)
                echo "default"
esac

for循环

基本语法

双小括号可以跟数学运算表达式

for((初始值;循环控制条件;变量变化))
do
程序
done

实操1+到100

sum=0
for((i=0;i<=100;i++))
do 
	sum=$[$sum+i]
	done
	echo $sum
循环中的$@和$*有什么区别, 如果没被引号引起来的化都是一行一行的打印输出的,  $*会把数据显示为一行输出

while

a=1
while [ $a -le $1]
do 
sum=$[$sum+$a]
a=$[$a+1]
done
echo $sum

控制台输入

read 选项 参数

选项 -p: 指定读取值时的提示符

-t: 指定读取时的等待的时间,如果-t不加默认一直等待

参数:变量:指定读取值的变量名

提示7秒内,读取控制台输入的名字

read -t 7 -p "name in 7": NN
echo $NN

系统函数

basename

basename 会删除掉所有的前缀包括最后一个(/)字符然后将字符串形式显示出来
basename可以理解为路径里的文件名称
选项:suffx为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉

dirname

dirname文件绝对路径,从给定的包含绝对路径的文件名中去除文件名,然后返回剩下的路径
可以理解为取文件路径的绝对路径

date 显示当前日期

date
2022年 06月 23日 星期四 15:06:40 CST
date +%s
1655968039

案例:根据控制台输入生成文件附带随机字符

#!/bin/bash
filename="$1"_log_$(date +%s)
echo $filename
~                     
./hello.sh player3
 player3_log_1655968339

调用系统函数

$(函数名 )

自定义函数

function name() {
    statements
    [return value]
}
对各个部分的说明:

    function是 Shell 中的关键字,专门用来定义函数;
    name是函数名;
    statements是函数要执行的代码,也就是一组语句;
    return value表示函数的返回值,其中 return 是 Shell 关键字,专门用在函数中返回一个值;这一部分可以写也可以不写。


由{ }包围的部分称为函数体,调用一个函数,实际上就是执行函数体中的代码。
函数定义的简化写法

如果你嫌麻烦,函数定义时也可以不写 function 关键字:

    name() {
        statements
        [return value]
    }

如果写了 function 关键字,也可以省略函数名后面的小括号:

    function name {
        statements
        [return value]
    }

我建议使用标准的写法,这样能够做到“见名知意”,一看就懂。
 Shell 也不限制定义和调用的顺序,你可以将定义放在调用的前面,也可以反过来,将定义放在调用的后面。


经验:
1.必须在调用函数地方之前,先声明函数,shell脚本是逐行执行的,不会像其他语言一样先编译
2.函数返回值,只能通过$?系统变量获得,可以显示加return 返回,如果不加,将以最后一条命令运行结果,将返回值,return后跟数值
(0-255) 



    #!/bin/bash
     
    function getsum(){
    local sum=0
     
    for n in $@
    do
    ((sum+=n))
    done
     
    return $sum
    }
     
    getsum 10 20 55 15 #调用函数并传递参数
    echo $?

将shell指令结果保存到变量

方法一: 反引号

#!/bin/bash

a=`ls -l; pwd; date;`
echo "$a"

b=`ls -l
 pwd
 date`
echo "$b"

方法二:使用 $()

#!/bin/bash
a=$(ls -l)
echo "$a"

nohup解决后台启动卡住的问题

nohup后台运行程序

nohup java -jar /root/demo*.jar >mylog.log 2>&1 &

后台运行指定某个文件,这样就不会提示我们指定哪个文件的问题 了,后面2>&1 &是标准的写法

数据流重定向:
数据流重定向就是将某个命令执行后应该要出现在屏幕上的数据传输到其他地方
标准输入:代码为0,使用<或<<
标准输出:代码为1,使用>或者>>
标准错误输出:代码为2,使用2>或者2>>

使用脚本杀死进程

-z 空值判断

#获取正在运行pid
pid=`-ef |grep $1 | grep 'java -jar | awk '{printf $2}'`
#如果pid为空,提示一下,否则执行kill命令
if[ -z $pid]
#使用 -z 做空值判断
then 
	echo "$appname not started"
	else 
	kill -9 $pid
fi

shell-命令工具

cut

cut命令切割将字符字段输出参数-f 列号,提取第几列 -d 分隔符,按照指定分隔符分割列。

案例:cut.txt

dong shen
guan zhen
wo    wo
lai  lai
le	 le

1.切割第一列

cut -d " " -f 1 cut.txt

2.切割第二第三列

cut -d " " -f 2,3 cut.txt

3.切割出guan

1.先过滤出cat cut.txt |grep guan
guan的字。
2.cat cut.txt |grep guan|cut  -d ' '  -f 1
posted @ 2022-06-23 17:26  三号小玩家  阅读(94)  评论(0编辑  收藏  举报
Title
三号小玩家的 Mail: 17612457115@163.com, 联系QQ: 1359720840 微信: QQ1359720840