IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Shell学习与总结(1) -> 正文阅读

[系统运维]Shell学习与总结(1)

Shell

Shell的作用是解释执行用户的命令,用户输入一条命令,Shell就解释执行一条,这种方式称为交互式(Interactive),Shell还有一种执行命令的方式称为批处理(Batch),用户事先写一个Shell脚本(Script),其中有很多条命令,让Shell一次把这些命令执行完,而不必一条一条地敲命令。Shell脚本和编程语言很相似,也有变量和流程控制语句,但Shell脚本是解释执行的,不需要编译,Shell程序从脚本中一行一行读取并执行这些命令,相当于一个用户把脚本中的命令一行一行敲到Shell提示符下执行。

当前用户用的shell

vim /etc/passwd
其中最后一列显示了用户对应的shell类型
root:x:0:0:root:/root:/bin/bash
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
syslog:x:101:103::/home/syslog:/bin/false
itcast:x:1000:1000:itcast,,,:/home/itcast:/bin/bash
ftp:x:115:125:ftp daemon,,,:/srv/ftp:/bin/false
root:x:0:0:root:/root:/bin/bash
解释:
root 用户名
x 表示密码通过加密放到了shadow
0 用户id
0 组id
root 用户描述
/root home目录地址
/bin/bash 用户登录之后执行的第一条命令

如果用户启动的第一条命令不是shell,就执行完命令就退出了。

确定当前用户用什么shell

echo $SHELL

修改当前用户的shell

chsh

用户在命令行输入命令后,一般情况下Shell会fork并exec该命令,但是Shell的内建命令例外,执行内建命令相当于调用Shell进程中的一个函数,并不创建新的进程。以前学过的cd、alias、umask、exit等命令即是内建命令,凡是用which命令查不到程序文件所在位置的命令都是内建命令,内建命令没有单独的man手册,要在man手册中查看内建命令,应该执行man bash-builtins或者help

编写一个简单的脚本test.sh:

#!/bin/sh
echo HelloWorld
cd ..
ls

1、Shell脚本中用#表示注释,相当于C语言的//注释。但如果#位于第一行开头,并且是#!(称为Shebang)则例外,它表示该脚本使用后面指定的解释器/bin/sh解释执行。如果把这个脚本文件加上可执行权限然后执行:
默认权限为0664:-rw-rw-r-- 1 kimi kimi 35 3月 15 10:25 test.sh

chmod a+x test.sh 
./test.sh

虽然执行了,但当前目录不会变,因为是启动一个子进程,父进程的当前目录不会更改。要提前说明使用什么解释器,在脚本中的第一句指定:#!/bin/sh

2、当我们没办法调整脚本权限时,其实exec还有另外一种机制,如果要执行的是一个文本文件,并且第一行用Shebang指定了解释器,则用解释器程序的代码段替换当前进程,并且从解释器的_start开始执行,而这个文本文件被当作命令行参数传给解释器。因此,执行上述脚本相当于执行程序 /bin/sh ./test.sh

3、以这种方式执行不需要test.sh文件具有可执行权限。
如果将命令行下输入的命令用()括号括起来,那么也会fork出一个子Shell执行小括号中的命令,一行中可以输入由分号;隔开的多个命令,比如: (cd ..;ls -l)

和上面两种方法执行Shell脚本的效果是相同的,cd …命令改变的是子Shell的PWD,而不会影响到交互式Shell。命令:cd ..;ls -l 则有不同的效果,cd …命令是直接在交互式Shell下执行的,改变交互式Shell的PWD。

4、这种方式相当于这样执行Shell脚本:source ./test.sh或者 . ./test.sh,利用 source或者.(同个意思)命令是Shell的内建命令,这种方式也不会创建子Shell,而是直接在交互式Shell下逐行执行脚本中的命令,source可能会改变当前目录

基本语法

Shell变量通常由字母加下划线开头,由任意长度的字母、数字、下划线组成。

在Shell中定义或赋值一个变量:VARNAME=value

注意等号两边都不能有空格,否则会被Shell解释成命令和命令行参数。
变量的使用,用$符号跟上变量名表示对某个变量取值,变量名可以加上{}花括号来表示变量名的范围:

echo $VARNAME
echo ${VARNAME}_suffix   #使用花括号来分离VARNAME和_suffix,不至于把VARNAME_suffix当做变量名

shell变量

全局变量:shell中不适用任何修饰符修饰的变量都是全局变量,不管函数内还是函数外都一样,从声明周期开始到脚本结束,都是其生命周期

局部变量:用local修饰,只能声明在函数内,从声明语句调用开始一直到函数结束

shell变量只能在当前shell中传递,跨进程不能使用,除非是用环境变量

环境变量
是操作系统自带的,每一个进程都会有,当启动一个子进程时,环境变量时从父进程拷贝到子进程,环境变量是单向传递,只能父进程->子进程。

export VARNAME=value

子进程

#!/bin/bash
echo "this is in sub script"
echo $globalVar1
echo "sub script end"
echo $environVar
#子进程修改环境变量
export environVar="2222222"

父进程

#!/bin/bash
globalVar1="hello"
function test()
{
    globalVar2="world"
    local localVar="itcast"
    echo $localVar
}
#调用函数
test
echo $globalVar1 $globalVar2 $localVar
export environVar="this is in environ"
#调用子脚本
./subScript.sh
#验证子进程修改环境变量之后父进程有没有改变
echo $environVar
#删除变量
unset globalVar1
echo "globalVar1=" $globalVar1

结果程序
在这里插入图片描述
删除变量

用来删除已经定义的变量,包括本地和环境变量:unset VARNAME

文件名代换
这些用于匹配的字符称为通配符(Wildcard),如:* ? [ ] 具体如下:

  1. * 匹配0个或多个任意字符
  2. ? 匹配一个任意字符
  3. [若干字符] 匹配方括号中任意一个字符的一次出现

在这里插入图片描述
在这里插入图片描述
参数扩展:touch {1,2,3,4}.txt
在这里插入图片描述
在这里插入图片描述
参数扩展文件不一定要存在

命令代换

由“`”反引号括起来的也是一条命令,Shell先执行该命令,然后将输出结果立刻代换到当前命令行中。

算术代换

$(())中只能用±*/和()运算符,并且只能做整数运算。
$[base#n],其中base表示进制,n按照base进制解释,后面再有运算数,按十进制解释。

转义字符

和C语言类似,\在Shell中被用作转义字符,用于去除紧跟其后的单个字符的特殊意义(回车除外),换句话说,紧跟其后的字符取字面值

#datatime.sh
DATE=`date`
echo $DATE

#也可以
DATE=$(date)
#!/bin/bash
#dateTime=`date`
dateTime=$(date)
echo "dateTime is " $dateTime

#touch 1.txt
#$0 是当前路径
#获取当前脚本所在路径 ,在这个路径touch一个1.txt
curPath=$(cd `dirname $0`;pwd)
touch $curPath/1.txt


var=45
var2=2
echo $[var+3]
echo $((var+3))
echo $((var*var2))
echo $(($var*$var2))

//八进制的10 再加上11
echo $[8#10+11]

#这个等价于./bin/bash
$SHELL
#这个就是字面值
\$SHELL


var="a b"
./a.out $var
./a.out "$var"

#创建两个文件
touch $var
#创建一个文件
touch "$var"

注意

各种UNIX命令都把-号开头的命令行参数当作命令的选项,而不会当作文件名。如果非要处理以-号开头的文件名,可以有两种办法:
touch ./-hello 或者 touch -- -hello

\还有一种用法,在\后敲回车表示续行,Shell并不会立刻执行命令,而是把光标移到下一行,给出一个续行提示符>,等待用户继续输入,最后把所有的续行接到一起当作一个命令执行。例如:

 ls \
> -l
(ls -l命令的输出)

单引号

和C语言不同,Shell脚本中的单引号和双引号都是字符串的界定符,而不是字符的界定符。单引号用于保持引号内所有字符的字面值,即使引号内的\和回车也不例外,但是字符串中不能出现单引号。如果引号没有配对就输入回车,Shell会给出续行提示符,要求用户把引号配上对。

kimi$ echo '$SHELL'
$SHELL
kimi$ echo 'ABC\(回车)
> DE'(再按一次回车结束命令)
ABC\
DE

双引号

被双引号括住的内容,将被视为单一字串。它防止通配符扩展,但允许变量扩展。这点与单引号的处理方式不同。支持变量的扩展。使用变量之前,如果变量是作为参数才传递的,要习惯性地对变量添加双引号。

kimi$ DATE=$(date)
kimi$ echo "$DATE"
kimi$ echo '$DATE'
kimi$ VAR=200
kimi$ echo $VAR	
200
kimi$ echo '$VAR'
$VAR
kimi$ echo "$VAR"
200

Shell表示真假

直接使用某条命令的返回状态来确定
main 返回 0 为真, 返回 非0 为假

条件测试

命令test[ 可以测试一个条件是否成立,如果测试结果为真,则该命令的Exit Status为0,如果测试结果为假,则命令的Exit Status为1(注意与C语言的逻辑表示正好相反)。

[ -d DIR ] 如果DIR存在并且是一个目录则为真
[ -f FILE ] 如果FILE存在且是一个普通文件则为真
[ -z STRING ] 如果STRING的长度为零则为真
[ -n STRING ] 如果STRING的长度非零则为真
[ STRING1 = STRING2 ] 如果两个字符串相同则为真
[ STRING1 == STRING2 ] 同上
[ STRING1 != STRING2 ] 如果字符串不相同则为真
[ ARG1 OP ARG2 ] ARG1和ARG2应该是整数或者取值为整数的变量
OP是-eq(等于)-ne(不等于)-lt(小于)-le(小于等于)-gt(大于)-ge(大于等于)之中的一个

若中括号中是一个命令,则左右要留空格

[ ! EXPR ] EXPR可以是上表中的任意一种测试条件,!表示“逻辑反()[ EXPR1 -a EXPR2 ] EXPR1和EXPR2可以是上表中的任意一种测试条件,-a表示“逻辑与”
[ EXPR1 -o EXPR2 ] EXPR1和EXPR2可以是上表中的任意一种测试条件,-o表示“逻辑或”

分支

和C语言类似,在Shell中用if、then、elif、else、fi这几条命令实现分支控制。这种流程控制语句本质上也是由若干条Shell命令组成的

if [ -f ~/.bashrc ]; then
	. ~/.bashrc
fi 

其实是三条命令,if [ -f ~/.bashrc ]是第一条,then . ~/.bashrc是第二条,fi是第三条。如果两条命令写在同一行则需要用;号隔开,一行只写一条命令就不需要写;号了,另外,then后面有换行,但这条命令没写完,Shell会自动续行,把下一行接在then后面当作一条命令处理。和[命令一样,要注意命令和各参数之间必须用空格隔开。if命令的参数组成一条子命令,如果该子命令的Exit Status为0(表示真),则执行then后面的子命令,如果Exit Status非0(表示假),则执行elif、else或者fi后面的子命令。if后面的子命令通常是测试命令,但也可以是其它命令。Shell脚本没有{}括号,所以用fi表示if语句块的结束。

#!/bin/bash

if [ -f /bin/bash ]
then
    echo "/bin/bash is a file"
else
    echo "/bin/bash is not a file"
fi

#冒号就是不做任何事
if :
then
    echo "always true"
fi

if false
then
    : 
else
    echo "always false"
fi

var=1
var2=2

if [ $var -eq 1 ] && [ $var2 -eq 2 ] 
then
    echo "yes"
fi

#!/bin/bash
echo "Is it morning? Please answer yes or no!"
#读取用户输入的一个变量
read YES_OR_NO
if [ "$YES_OR_NO" = "yes" ]
then
    echo "Good morning"
elif [ "$YES_OR_NO" = "no" ] ; then
    echo "Good afternoon"
else
    echo "Not recognized"
    :
fi

“:”是一个特殊的命令,称为空命令,该命令不做任何事,但Exit Status总是真。

Shell还提供了&&和||语法,和C语言类似,具有Short-circuit特性,很多Shell脚本喜欢写成这样:

test "$(whoami)" != 'root' && (echo you are using a non-privileged account;)

&&相当于“if…then…”,而||相当于“if not…then…”。
&&和||用于连接两个命令,而上面讲的-a和-o仅用于在测试表达式中连接两个测试条件,要注意它们的区别,例如:

test "$VAR" -gt 1 -a "$VAR" -lt 3

和以下写法是等价的

test "$VAR" -gt 1 && test "$VAR" -lt 3

case/esac

case命令可类比C语言的switch/case语句,esac表示case语句块的结束。C语言的case只能匹配整型或字符型常量表达式,而Shell脚本的case可以匹配字符串和Wildcard,每个匹配分支可以有若干条命令,末尾必须以;;结束,执行时找到第一个匹配的分支并执行相应的命令,然后直接跳到esac之后,不需要像C语言一样用break跳出。

#! /bin/sh

echo "Is it morning? Please answer yes or no."
read YES_OR_NO
case "$YES_OR_NO" in
yes|y|Yes|YES)
	echo "Good Morning!";;
[nN][Oo])
	echo "Good Afternoon!";;
*)
	echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
	return 1;;
esac

使用case语句的例子可以在系统服务的脚本目录/etc/init.d中找到。这个目录下的脚本大多具有这种形式(以/etc/init.d/nfs-kernel-server为例):

case "$1" in
	start)
		...
	;;
	stop)
		...
	;;
	reload | force-reload)
		...
	;;
	restart)
		...
	*)
	    log_success_msg"Usage: nfs-kernel-server {start|stop|status|reload|force-reload|restart}"
	;;
esac

启动nfs-kernel-server服务的命令是

$ sudo /etc/init.d/nfs-kernel-server start

$1是一个特殊变量,在执行脚本时自动取值为第一个命令行参数,也就是start,所以进入start)分支执行相关的命令。同理,命令行参数指定为stop、reload或restart可以进入其它分支执行停止服务、重新加载配置文件或重新启动服务的相关命令。

循环

for/do/done

#!/bin/bash

for FRUIT in apple banana pear 
do
    echo "I like $FRUIT"
done


# 计算 1加到100的结果  5050
sum=0
for i in {1..100}
do
    sum=$[$sum+$i]
done
echo $sum

# 遍历当前目录,是文件就输出xxx是一个文件,是目录的就输出xxx是一个目录
# 等价于 for f in ’ls‘
for f in $(ls)
do
    if [ -f "$f" ]
    then
        echo "$f is a regular file"
    elif [ -d "$f" ]
    then
        echo "$f is a directory"
    else
        echo "$f is not recognized"
    fi
done

# 输出5050
sum=0
count=1
while [ $count -le 100 ]
do
    sum=$[$sum+$count]
    count=$[$count+1]
done
echo $sum

while/do/done

#!/bin/bash

echo "Please input paswd"
read try
errCount=1
while [ "$try" != "secret" ]
do
    if [ "$errCount" -ge 5 ]
    then
        echo "Error 5 times , exit"
        break
    fi
    echo "Sorry , try again!"
    read try
    errCount=$[$errCount+1]
done
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-03-16 22:58:21  更:2022-03-16 23:01:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 1:16:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码