shell 学习笔记

1、shell 概述

shell 是一个命令行解释器,接收应用程序、用户的命令,然后调用操作系统的内核,shell可以当成是一个功能强大的编程语言,易编写、易调试、灵活性强。

几种常见的shell

sh、 bash、chs等等,是由不同的组织机构开发的不同的 Shell,它们各有所长,有的占用资源少,有的支持高级编程功能,有的兼容性好,有的重视用户体验;

echo $SHELL   
// 查看系统默认的shell

cat /etc/shells 
//当前Linux系统可用的shell都记录在 /etc/shells文件中

ls -l /bin/sh 
// 在现代的 Linux 上,sh 已经被 bash 代替,/bin/sh往往是指向/bin/bash的符号链接。

 2、写一个hellworld.sh文件

创建文件夹,并创建一个shell文件
mkdir test
cd test
vim hello.sh

以下是hello.sh文件内容
###################
#!/bin/bash  -->指定解析器
echo "hello world"


保存后运行文件,当前文件夹下面可直接运行
bash hello.sh  -->本质是bash解析器帮你执行脚本,所有不需要权限

先给hello.sh赋权限,可用省略bash
chomd +x hello.sh
hello.sh  --> 本质是脚本自己需要执行,因此需要执行权限

3、变量

3.1系统预定义变量

常见的系统变量
$HOME  $PWD 、$SHELL 、$USER 等等

使用env命令,可用直接查看当前系统所有环境变量
env

查看系统变量的值
echo $HOME

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

3.2自定义变量

1、基本语法

定义变量: 变量名=变量值,注意等号前后不能有空格
my_test=hello

修改变量: 变量名=变量值, 直接修改变量值即可
my_test=Hello

父shell的值可以让子shell读到,提升为全局变量
export my_test

子shell此时可以读到my_test,也可以修改my_test,但是子shell中的修改不会影响到父shell中的值
看父子的继承关系
ps -f

定义只读变量
readonly a=5  -- 不能unset 只读变量

撤销变量: unset 变量名

3.3特殊变量

基本语法

$n 
n为数字,$0代表该脚本名称,$1~$9代表第一个到第九个参数,超过10的参数,需要用大括号包含,如${10}

echo "hello $1" xiaoming
--> hello  xiaoming

$#
获取所有输入参数个数,常用于循环,判断参数的个数是否正确以及加强脚本的健壮性

$*
代表命令行中所有的参数,$*把所有的参数看成一个整体

$@
代表命令行中所有的参数,$@把每个参数区分对待

$?
最后一次执行的命令的返回状态,如果遍历的值为0,证明上一个命令正确执行,
如果非0(具体是哪个数,由命令自己决定),则证明上一个命令执行不正确了

4、运算符

基本语法

$((运算式)) 或者 $[运算式]

计算2+3的值
$((2+3))
$[2+3]

expr 2 + 3 //加号左右两边要有空格,计算结果5
expr 2+3 //加号左右两边没有空格,结果是字符串 2+3

5、条件判断

基本语法

1、test condition  // test后面跟条件表达式

a=hello  //定义a=hello,等号前后不能有空格
test $a = hello // 测试a是否等于hello,注意等号前后要有空格
echo $?  // 输出0,说明上面的结果是对的

2、[ condition ] // 中括号里面加条件表达式,注意condition前后都要有空格

[ $a = hello ] // 测试a是否等于hello
echo $?  // 输出0,说明上面的结果是对的

注意,条件非空则返回true 如[ aaa ],条件为空返回false 如[  ]


常用条件判断

1、两个整数之间比较

-eq 等于
-ne 不等于
-lt 小于 less than
-gt 大于 greater than
-le 小于等于 less equal
-ge 大于等于 greater equal

如果是字符串之间的比较,用等号 = 判断相等,用 != 判断不等

2、按照文件权限进行判断
-r 有读的权限 read   [ -r hello.sh ]
-w 有写的权限 write  [ -w hello.sh ]
-x 有执行的权限  execute  [ -x hello.sh ]

3、按照文件类型进行判断
-e  文件存在
-f  文件存在并且是一个常规的文件file
-d  文件存在并且是一个目录directory


4、多条件判断
逻辑与 &&
逻辑或 ||
-a 逻辑与
-o 逻辑或

if [ $a -gt 18] && [ $a -lt 35]; then echo ok; fi
if [ $a -gt 18 -a $a -lt 35]; then echo ok; fi


可以实现类似三元表达式的效果
[ condition ] && echo ok || echo notok

6、流程控制

1、if判断

基本语法
##########################
单分支
if [ condition ];then
    程序
fi

或者
if [ condition ]
then
    程序
fi

例子
if [ $a -gt 18 ] && [ $a -lt 35 ]; then echo ok; fi
if [ $a -gt 18 -a $a -lt 35 ]; then echo ok; fi
##############################################

多分支判断1

if [ condition ]
then
    xxx
eles
    yyy
fi

例子
if [ $a -le 18 ]
then
    echo "未成年"
else
    echo "成年人"
fi

###############################################

多分支判断2

if [ condition ]
then
    xxx
elif [ condition ]
then (#跟在if后面就要加个then)
    yyy
eles
    zzz
fi

例子
if [ $a -le 18 ]
then
    echo "未成年"
elif [ $a -ge 60 ]
then  
    echo "老年人"
else
    echo "成年人"
fi

 

2、case语句

基本语法

case $变量名 in    #case 行位必须为in
"值1")      #值1可以加引号,也可以不加,匹配必须以)作为结束
    #如果变量的值等于 值1,则执行此段程序
;;  #双分号标识命令序列结束,相当于break
"值2")
   #如果变量的值等于 值2,则执行此段程序 
;; 
*)   #表示默认模式,相当于default
    #如果变量的值和上述都不匹配,则执行此段程序 
;;
esac


例子

case $a in
1)
    echo "one"
;;
2)
    echo "two"
;;
3)
    echo "three"
;;
*)
    echo "other"
;;
esac

3、 for 循环

基本语法1:

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

例子:从1加到100
sum=0
for (( i=1;i<=100;i++ )) #因为用到了双小括号,里面可以直接用数学计算式,但是建议还是用[]
do
    sum=$[ $sum + $i ]  #取值的时候,前面要加上$
done
echo $sum



基本语法2

for 变量 in 值1 值2 值3 ...
do
    程序
done

例子

循环打印
for os in linux windows macos
do
    echo $os
done


计算1~100的和
for i in {1..100}
do
    sum=$[ $sum + $i ]
done
echo $sum


#测试$* $@,将下列写在脚本文件里

#!bin/bash
echo '========$*=========='
for param in $*
do
    echo $param
done

echo '========$@=========='
for param in $@
do
    echo $param
done

# 执行上述脚本文件,后面传入参数为 a b c d e 
# 打印的结果是相同的,是分别将参数打印出来
原因 : $* $@在脚本文件中不加引号,效果是相同的

#!bin/bash
echo '========$*=========='
for param in "$*"
do
    echo $param
done

echo '========$@=========='
for param in "$@"
do
    echo $param
done

# 执行上述脚本文件,后面传入参数为 a b c d e 
# 打印的结果是不同的
# "$*" 是将传入的参数当作一个参数打印
# "$@" 是将传入的参数按照空格分割打印
原因 : $* $@在脚本文件中加引号,效果不相同
4、 while循环

while [ 条件表达式 ]
do
    程序
done

例子,1加到100

i=1
sum=0
while [ i -le 100 ]
do
    sum=$[ $sum + $i ]   # let sum+=i
    i=$[ $i + 1 ]        # let i++
done
echo sum

7、read 读取控制台输入

基本语法

read (选项) (参数)

选项:
    -p: 指定读取值时的提示符号
    -t: 指定读取值时等待的时间(秒),如果不加则一直等待
参数
    变量:指定读取值的变量名


例子:7s内,读取控制台输入的名称

#!/bin/bash

read -t 7 -p "请输入你的名字" name
echo "welcome $name"

8、函数

1、系统函数

1.1 basename

基本语法
basename 字符串 后缀  #就是取最后一个/后面的内容,如果同时传入了后缀,则会把后缀也去掉

basename /root/aaa/bbb/ccc.txt
# ccc.tx
basename /root/aaa/bbb/ccc.txt .txt
# ccc


1.2 dirname

基本语法
dirname 文件绝对路径 (从给定的包含绝对路径的文件名中去除文件名,即非目录部分,
然后返回剩下的目录的部分)

dirname /root/aaa/bbb/ccc.txt
# /root/aaa/bbb
2、自定义函数

基本语法 #带[]表示可以省略
[ function ] functionName[()]
{
    Action;
    [return i;]
}

注意事项:
1、必须在函数调用之前先声明函数,shell脚本时逐行运行,不会像其他语言一样先编译
2、函数返回值只能通过$?系统变量获得,可以显示的加  return 返回,
如果不加,则以最后一条命令运行结果作为返回值,return后面跟的数值 0~255

例子,计算两数字之和
function add()
{
    s=$[$1 + $2] #位置参数
    return $s
}

read -p "请输入第一个参数" a
read -p "请输入第二个参数" b

add $a $b  #调用函数
echo $?
# 这样写会有一些问题:即return只能返回0~255的数值,
# 如果计算结果超出这个范围,虽然不会报错,单数结果不准确

改写:
function add()
{
    s=$[$1 + $2] #位置参数
    echo $s  # 返回计算结果改为输出计算结果
}

read -p "请输入第一个参数" a
read -p "请输入第二个参数" b

sum=$(add $a $b)  
#调用函数,没有return,则以最后一条命令作为返回值,
#将这个返回值赋值给sum ,然后输出sum
echo $sum

9、正则表达式

1、^ 匹配行首
cat /ect/password | grep ^a #匹配每行以a开头的行

2、$ 匹配行尾
cat /ect/password | grep bash$ #匹配每行以bash结尾的行

^$ 匹配的是空行
^xxx$ 匹配的是以xxx为内容的行

3、. 匹配的是任意一个字符
cat /ect/password | grep r..t  #匹配包含 r..t的行,可以是root、r/ht等等

4、* 不单独使用,和上一个字符连用,表示匹配上一个字符0次或者多次
cat /ect/password | grep ro*t  #匹配 rt rot root rooot等

.*表示任意一个字符出现任意次,就说明匹配到的是任意字符,也可以是空

^a.*bash$  #表示每行以a开头,bash结尾的任意行
^a.*var.*bash$  #表示每行以a开头,bash结尾,中间带var的任意行

5、字符区间,中括号 []
[6,8]  匹配6和8
[0-9]  匹配0到9
[0-9]* 匹配任意长度的数字串
[a-z]  匹配小写字母
[a-z]* 匹配任意长度小写字母字符串


6、\ 表示转义

10、文本处理工具

1、 cut

负责剪切数据用的,cut命令从文件的每一行剪切字节、字符和字段并输出

基本用法
cut [选项参数] filename

说明 :默认分隔符是制表符

选项参数说明:
-f    列号,提取第几列
-d    分隔符,按照指定分隔符分割列,默认制表符“\t”
-c    按照字符进行切割,后面加n标识取第几列 比如 -c 1


定义 文件 test.txt
======================
aaa aaa
bbb bbb
ccc    ccc
ddd    ddd

======================

cut -d " " -f 1 text.txt  #按照空格分割,截取第一列

cut -d " " -f 2,3 text.txt #按照空格分割,截取第二,三列

cat /etc/password | grep bash$ | cut -d ":" -f 1,6,7  
# cat 查看password文件,后面跟管道符查询以bash结尾的行
# 然后跟管道符 使用cut,表示对前面过滤到的信息进行裁剪
# 以:为分隔符,取1.6.7列  ------取出来的值还是用原来的分隔符进行拼接

cat /etc/password | grep bash$ | cut -d ":" -f 1,6-
# 取第一列,第6列以以后所有的

cat /etc/password | grep bash$ | cut -d ":" -f -4
# 取包括第4列及之前的

ifconfig ens33 | grep netmask | cut -d " " if 10

 

2、 awk

强大的文本分析工具,把文件逐行读入,以空格默认分割符将每行切片,切开的部分在分开处理

基本用法

awk [选项参数] '/pattern1/{action1} /pattern2/{action2} ...' filename

pattern: 表示awk在数据中查找的内容,就是匹配模式,正则,没有正则就可以省略
action: 在找匹配内容时所执行的一系列命令

选项参数
-F 制定文件分隔符,默认空格
-v 赋值一个用户定义变量


例子:
1、搜素password文件中,以root开头的所有行,并输出该行的第1列和第7列,中间以“,”分割

cat /etc/password |grep ^root | cut -d ":" -f 7

cat /etc/password | awk -F ":" '/^root/{print $7}'

cat /etc/password | awk -F ":" '/^root/{print $1","$7}'   
#双引号包裹 ,  做字符串拼接
#如果没有双引号包裹 , 是默认空格分割
#如果$1$7 或者$1 $7 是直接拼接在一起,没有空格分割 


2、在password文件中,输出第1列和第7列,中间以“,”分割,并在所有行之前添加“user,shell”,
所有行之后加“end,byebye”

cat /etc/password | awk -F ":" 'BEGIN{print "user,shell"} {print $1","$7} END{print "end,byebye"}'

BEGIN : 在所有数据读取行之前执行     
END : 在所有数据执行之后执行

3、将password文件中用户的id(第3列)数值增加1并 输出

cat /ect/password | awk -F ":" '{print $3+1}'

cat /ect/password | awk -v i=1  -F ":" '{print $3+i}' #用变量


4、awk的内置变量
FILENAME    文件名
NR    已读的记录数(行号)
NF    切割后,列的个数


输出password文件中每行的列数
awk -F ":" '{print "filename:"FILENAME "行数:"NR "列数:"NF}' /ect/password


输出ifconfig中的空行
ifconfig | grep -n ^$   # -n是输出行号,但是默认的行号后面带冒号:,无法更改

ifconfig | awk '/^$/ {print NR}'  # 这样就没有冒号了


输出ipconfig中的ip

ifconfig | grep netmask | cut -d " " -f 10  #cut分割后,数第10个是ip

ifconfig | awk '/netmask/{print $2}'   #awk 分割空格后,为null的不考虑,第二个不为空的为ip

11、综合应用案例

11.1 归档文件

需求:
实现一个每天对指定目录归档备份的脚本,输入一个目录名称(末尾不带/),
将目录下所有文件按天归档保存,并将归档日期附加在归档文件名上,
放在/root/archive下。

归档命令:tar
-c 表示归档,-z表示同时进行压缩,得到的文件后缀名为.tar.gz


脚本的实现:
==========================================================

#!/bin/bash

#首先判断输入参数的个数是否为1
if [ $# -ne 1 ]
then
    echo "参数个数错误"
    exit
fi

#从参数中获取目录名称
if [ -d $1 ]
then
    echo  #做后序处理
else
    echo "目录不存在"
    exit
fi

DIR_NAME=$(basename $1) #获取文件名称
DIR_PATH=$(cd $(dirname $1); pwd)  #cd进到文件所在的目录,然后pwd获取绝对路径

#获取当前日期
DATE=$(date +%y%m%d)

#定义生成的归档文件名称
FILE=archive_${DIR_NAME}_${DATE}.tar.gz
DEST=/root/archive/${FILE}

#开始归档目录文件
echo "开始归档"
echo

tar -czf $DEST ${DIR_PATH}/${DIR_NAME}  #前面是归档文件名,后面是要压缩的文件地址

if [ $? -eq 0 ]
then 
    echo "归档成功"
    echo "归档文件为:$DEST"
else
    echo "归档失败"
fi

exit


==========================================================


定时任务
crontab -e:  编辑当前用户的定时任务列表
crontab -l:  查看当前用户的定时任务列表
crontab -r:  删除当前用户的定时任务列表

Linux 定时任务调度(crontab),太实用了!

11.2 发送消息

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习Shell命令时,以下是一些重要的注意事项和学习建议: 1. 基本语法:Shell命令通常由命令名称和参数组成。命令名称是要执行的操作,而参数则提供了命令所需的信息。了解Shell命令的基本语法是学习的第一步。 2. 命令帮助:大多数Shell都提供了内置的命令帮助功能。通过使用命令后跟`--help`或`-h`选项,或者使用`man`命令(例如`man ls`)来获取有关特定命令的详细信息。 3. 常用命令:有一些常见的Shell命令对于日常使用非常有用。这些包括`cd`(更改目录)、`ls`(列出目录内容)、`mkdir`(创建目录)、`rm`(删除文件或目录)等。逐步学习和掌握这些命令是很重要的。 4. 管道和重定向:Shell命令非常强大,可以通过管道和重定向符号将多个命令组合在一起。了解如何使用管道(`|`)将一个命令的输出作为另一个命令的输入,并使用重定向符号(`>`、`>>`、`<`)来控制输入和输出。 5. 脚本编写:Shell脚本是一种将多个命令组合在一起以自动化任务的方法。学习如何编写简单的Shell脚本可以提高工作效率。 6. 实践和练习:最重要的是进行实践和练习。尝试使用不同的Shell命令来完成各种任务,并在实际场景中应用所学知识。 记住,Shell命令的学习是一个逐步的过程。开始时可能会有些困惑,但随着实践和经验的积累,你会变得越来越熟练。希望这些提示对你有帮助!如有任何具体问题,随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值