Linux中shell脚本的学习第一天,编写脚本的规范,脚本注释、变量,特殊变量的使用等,包含面试题

4月7日没参加体侧的我自学shell的第一天

Shebang

计算机程序中,shebang指的是出现在文本文件的第一行前两个字符 #!

1)以#!/bin/sh 开头的文件,程序在执行的时候会调用/bin/sh, 也就是bash解释器

2)以#!/usr/bin/python 开头的文件, 代表指定python 解释器去执行

3)以#!/usr/bin/env 解释器名称, 是一种在不同平台上都能正确找到解释器的办法

shell 复制代码
# 输出变量的值
echo $SHELL

写一个简单的Python编译器的shell脚本

shell 复制代码
#! /usr/bin/python
# coding:utf-8
print("你好!")

# 如果解释器坏了,或者不能正确运行,就手动指定解释器,这里我的shell脚本的名称为hello.py
/usr/bin/python hello.py

脚本注释,脚本开发规范

1)在shell脚本中,#后面的内容代表注释掉的内容,提供给开发者或使用者观看,系统会忽略此行

2)注释可以单独写,也可以跟在命令后面

3)保持爱写注释的习惯,以便于以后回顾代码的含义,尽量使用英文

执行shell脚本的方式

1)bash script.sh 或 sh script.sh, 文件本身没有执行权限或没有写shebang,则使用的方法

2)使用 绝对/相对 路径执行脚本, 需要文件含有x权限(chmod +x 文件名)

3) source script.sh 或 . script.sh , 代表 执行的含义, source 等于点

4)少见的用法, sh < script.sh

什么是bash

1)bash是一个命令处理器, 运行在文本窗口中,并能执行用户直接输入的命令

2)bash还能从文件中读取Linux命令,称之为脚本

3)bash支持通配符、管道、命令替换、条件判断等逻辑控制语句

bash有诸多方便的功能,有助于运维人员提升工作效率

shell 复制代码
# history命令
-c 清空历史
-r 恢复历史

# 调用历史记录命令
# 感叹号+历史命令行ID
!! # 执行上一行命令,以及上下左右寻找

变量

特殊的变量,用于检测上一行的代码是否成功运行。

shell 复制代码
echo $?
0 # 表示运行成功
1-255 # 表示运行失败

注意:

单引号变量,不识别特殊语法

双引号变量,能识别特殊符号

eg.演示单引号,双引号的区别

shell 复制代码
name="奥利给"
echo ${name}
>> 奥利给
name2='${name}'
>> ${name}
name3="${name}"
>> 奥利给

1)每次调用bash/sh解释器执行脚本,都会开启一个子shell,因此不保留当前的shell变量,通过pstree命令检查进程树

2)调用source或者点符号是在当前shell环境加载脚本,因此保留变量

反引号的用法

shell 复制代码
name=`ls`
# 先会执行ls命令然后再把结果赋值给name

环境变量

1)每个用户都有自己的环境变量配置文件

~/.bash_profile ~/.bashrc

且以个人配置文件,优先加载变量,读取,以个人的优先生效

2)当你需要给所有用户都使用某个变量,写入全局即可/etc/profile

shell 复制代码
set # 输出所有变量,包括全局变量,局部变量(sh中定义的变量)
set |grep ^name # 用于查询指定的变量,此处是查询以name开头的变量。
set |wc -l # 用于统计全局变量的个数

env # 只显示系统的全局变量

declare # 输出所有的变量,如同set

export # 显示和设置环境变量的值

# 撤销环境变量
unset 变量名 # 用于删除变量或函数。

# 设置只读变量
readonly name='hello'
name='hi~'
>> -bash: name: 只读变量
系统保留环境变量关键字

bash内嵌套了诸多环境变量,用于定义bash的工作环境

shell 复制代码
export |awk -F '[ :=]' '{print $3}'
# 用于只显示系统环境变量的名称

bash支持多命令执行

shell 复制代码
ls /data/; cd/tmp/; cd /home; cd / data

特殊变量

参数传递:

shell 复制代码
$0 # 获取shell脚本文件名,以及路径
$n # 获取shell脚本的第n个参数,n在1~9之间,如$1, $2, $9,大于9则需要写,${10},参数空格隔开
$# # 获取执行shell脚本后面的参数总个数
$* # 获取shell脚本所有参数,不加引号等同于$@作用,加上引号"$*"作用是接收所有参数为单个字符串,"$1 $2..
$@ # 不加引号,效果同上,加引号,是接收所有参数为独立字符串,如"$1" "$2" "$3" ..., 空格保留

案例演示:我先新建了一个名为 special_var.sh的shell脚本

shell 复制代码
#!/bin/bash
echo '特殊变量 $0 $1 $2 ..的实践' # 单引号就是远洋输出
echo  '结果:' $0 $1 $2

echo '----------------------'
echo '特殊变量获取$# 获取参数总个数'
echo '结果:'	$#

echo '----------------------'
echo '特殊变量$* 实践'
echo '结果:'  $*

echo '----------------------'
echo '特殊变量$@ 实践'
echo '结果:' $@

效果如下:

shell 复制代码
bash special_var.sh li hao 2021 2022 2023 2024
>>
特殊变量 $0 $1 $2 ..的实践 
结果:special_var.sh li hao
-----------------------
特殊变量获取$# 获取参数总个数
结果:6
-----------------------
特殊变量$* 实践
结果:li hao 2021 2022 2023 2024
-----------------------
特殊变量$@ 实践
结果:li hao 2021 2022 2023 2024

面试题分析

shell 复制代码
$* 与 $@的区别?
$* 和 $@ 都表示传递给函数或脚本的所有参数
当$* 和 $@ 不被双引号包裹时,效果都是一样,都是将所有的参数当成一个整体输出,彼此之间空格隔开
但当他们被双眼号包""裹的时候,就有区别了:
"$*" 会把所有的参数从整体上来看当成一份数据,而不是把每一个参数都看做一份数据
"$@" 会把每一个参数单独对待,当成一个个不同的数据
在for循环中证明了"$*"和"$@"的区别
"$*"--》li hao 2024 2025 (只循环一次)
"$@" 	(把所有的数据都循环一遍,一共循环了4次)
--》
li
hao
2024
2025

案例体验:

我创建了一个名为different.sh 的shell脚本

shell 复制代码
#!/bin/bash
echo "print each param from \"\$*\""
for var in "$*"
do
	echo "$var"
done
echo "print each param from \"\$@\""
for var in "$@"
do 
	echo "$var"
done

效果如下:

shell 复制代码
bash different.sh li hao 2024 2025
>>
print each param from "$*"
li hao 2024 2025
print each param from "$@"
li
hao
2024
2025

特殊状态变量

shell 复制代码
$? # 上一次命令执行状态返回值,0正确,非0失败
$$ # 当前shell脚本的进程号
$! # 上一次后台进程的PID
$_ # 查看之前执行的命令,最后一个参数

脚本返回值,在学习shell函数编程之后,才能彻底理解,这个脚本在执行完毕后会返回一个数字ID,称之为返回值

案例:

​ 首先我创建了一个名为t1.sh的shell脚本

shell 复制代码
cat t1.sh
#!/bin/bash
# $#获取参数个数 -ne 不等于的情况 && 并且的意思

[ $# -ne 2 ] && {
	echo "must be two args"
	exit 119
	# 终止程序运行,且返回119状态码,提供给当前shell的$?变量,若是在函数里 可以return 119的用法
}
echo "没毛病,就是2个参数"

效果如下:

shell 复制代码
bash t1.sh li hao 2024
>>must be two args
echo $?
119
bash t1.sh li hao 
没毛病,就是2个参数
echo $?
>>0

面试题

怎样让程序在后台执行?

nohup xxx & 1> /dev/null

获取上次后台运行的PID,$!

shell 复制代码
nohup ping baidu.com & 1> /dev/null
>>[1] 21973
ps -ef|grep ping # 在所有正在运行的进程中查看包含ping的进程
>> root 21973 20999 0 16:34 pts/0 00:00:00 ping baidu.com
echo $!
>> 21973

获取当前的脚本ID

shell 复制代码
cat t1.sh
#!/bin/bash
# $#获取参数个数 -ne 不等于的情况 && 并且的意思

[ $# -ne 2 ] && {
	echo "must be two args"
	exit 119
	# 终止程序运行,且返回119状态码,提供给当前shell的$?变量,若是在函数里 可以return 119的用法
}
echo "没毛病,就是2个参数"
echo "当前的脚本ID是:$$"

运行效果如下:

shell 复制代码
bash t1.sh li hao
>> 没毛病,就是2个参数
>> 当前的脚本ID是:20001 # 每次运行完成后的脚本ID都不一样

$_获取上一次命令传入的最后一个参数

shell 复制代码
bash t1.sh li hao
...
echo $_
>> hao
相关推荐
Zww089119 分钟前
docker部署个人网页导航
运维·docker·容器
Flying_Fish_roe19 分钟前
linux-网络管理-网络配置
linux·网络·php
运维小白。。22 分钟前
Nginx 反向代理
运维·服务器·nginx·http
PeterJXL22 分钟前
Docker-compose:管理多个容器
运维·docker·容器
FuLLovers23 分钟前
2024-09-13 冯诺依曼体系结构 OS管理 进程
linux·开发语言
海王正在撒网26 分钟前
用 Docker 部署 Seafile 社区版
运维·docker·容器
王中阳Go28 分钟前
字节跳动的微服务独家面经
微服务·面试·golang
科技互联人生29 分钟前
中国数据中心服务器CPU行业发展概述
服务器·硬件架构
everyStudy1 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
luthane1 小时前
python 实现average mean平均数算法
开发语言·python·算法