当前位置: 首页 > news >正文

【Shell编程学习】Shell基础知识

【Shell编程学习】Shell基础知识

目录

  • 一、Shell简介
  • 二、Shell分类
    • 1、图形界面Shell(GUI Shell)
    • 2、命令行界面Shell(CLI Shell)
  • 三、第一个Shell脚本
    • 1、编辑shell脚本
    • 2、执行Shell脚本有三种方法:
      • 方法1:用bash解释器执行
      • 方法2:添加可执行权限
      • 方法3:source命令执行,以当前默认Shell解释器执行
  • 四、Shell变量
    • 1、系统变量
    • 2、普通变量与临时环境变量
      • 1)变量定义及命名规则
      • 2)普通变量与临时环境变量区别
    • 3、位置变量
    • 4、特殊变量
  • 五、变量引用
    • 1、自定义变量及引用
    • 2、将命令结果作为变量值
  • 六、双引号和单引号
  • 七、Shell注释
    • 1、单行注释
    • 2、多行注释

一、Shell简介

Shell是一个C语言编写的脚本语言,它是用户与Linux的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
用户输入命令交给Shell处理,Shell将相应的操作传递给内核(Kernel),内核把处理的结果输出给用户。流程示意图:
在这里插入图片描述
Shell工作在Linux内核之上。
Linux是一套免费试用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。
Linux基本思想有两点:第一,一切都是文件;第二,每个软件都有确定的用途。与Unix思想十分相近。

Shell 脚本的一些优点包括:

  • 自动化:Shell 脚本允许你自动化重复性任务和过程,节省时间并减少手动执行时可能出现的错误。
  • 可移植性:Shell 脚本可以在各种平台和操作系统上运行,包括 Unix、Linux、macOS,甚至通过使用模拟器或虚拟机在 Windows 上运行。
  • 灵活性:Shell 脚本高度可定制,可以轻松修改以满足特定需求。它们还可以与其他编程语言或实用程序结合,创建更强大的脚本。
  • 易访问性:Shell 脚本易于编写,不需要任何特殊工具或软件。它们可以使用任何文本编辑器进行编辑,并且大多数操作系统都有内置的 shell 解释器。
  • 集成:Shell 脚本可以与其他工具和应用程序集成,如数据库、Web 服务器和云服务,从而实现更复杂的自动化和系统管理任务。
  • 调试:Shell 脚本易于调试,大多数 shell 都内置调试和错误报告工具,可以帮助快速识别和修复问题。

二、Shell分类

1、图形界面Shell(GUI Shell)

GUI为Unix或者类Unix操作系统构造一个功能完善、操作简单以及界面友好的桌面环境。主流桌面环境有KDE,Gnome等。

2、命令行界面Shell(CLI Shell)

CLI是在用户提示符下键入可执行指令的界面,用户通过键盘输入指令,完成一系列操作。
在Linux系统上主流的CLI实现是Bash,是许多Linux发行版默认的Shell。还有许多Unix上Shell,例如:

  • Bourne Shell(/usr/bin/sh或/bin/sh)
  • Bourne Again Shell(/bin/bash)
  • C Shell(/usr/bin/csh)
  • K Shell(/usr/bin/ksh)
  • Shell for Root(/sbin/sh)
  • ……

在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash
#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序。

三、第一个Shell脚本

1、编辑shell脚本

打开文本编辑器(可以使用 vi/vim 命令来创建文件),新建一个文件 firstshell.sh,扩展名为 sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好。

[root@nieay linux]# vim firstshell.sh
[root@nieay linux]# cat firstshell.sh
#!/bin/bash
echo "Hello World!"

#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。
echo 命令用于向窗口输出文本。

2、执行Shell脚本有三种方法:

方法1:用bash解释器执行

[root@nieay linux]# bash firstshell.sh
Hello World!

当前终端会新生成一个子bash去执行脚本。

[root@nieay linux]# /bin/sh firstshell.sh
Hello World!

这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。

方法2:添加可执行权限

[root@nieay linux]# ll
-rw-r--r--.  1 root root       34 1010 10:09 firstshell.sh
[root@nieay linux]# chmod +x ./firstshell.sh #使脚本具有执行权限
[root@nieay linux]# ll
-rwxr-xr-x.  1 root root       34 1010 10:09 firstshell.sh
[root@nieay linux]# ./firstshell.sh	#执行脚本
Hello World!

注意:一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 firstshell.sh 是会找不到命令的,要用 ./firstshell.sh 告诉系统说,就在当前目录找。

方法3:source命令执行,以当前默认Shell解释器执行

[root@nieay linux]# source firstshell.sh
Hello World!

四、Shell变量

1、系统变量

在命令行提示符直接执行env、set查看系统或环境变量。env显示用户环境变量,set显示Shell预先定义好的变量以及用户变量。可以通过export导出成用户变量。
写Shell脚本时常用的系统变量:

变量注释
$SHELL默认Shell
$HOME当前用户家目录
$IFS内部字段分隔符
$LANG默认语言
$PATH默认可执行程序路径
$PWD当前目录
$UID当前用户ID
$USER当前用户
$HISTSIZE历史命令大小,可通过HISTTIMEFORMAT变量设置命令执行时间
$RANDOM随机生成一个0至32767的整数
$HOSTNAME主机名

2、普通变量与临时环境变量

1)变量定义及命名规则

普通变量定义:VAR=value
临时环境变量定义:export VAR=value
变量引用:$VAR

定义变量时,变量名不加美元符号($)。
变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。

变量名的命名须遵循如下规则

  • 只包含字母、数字和下划线: 变量名可以包含字母(大小写敏感)、数字和下划线 _,不能包含其他特殊字符。
  • 不能以数字开头: 变量名不能以数字开头,但可以包含数字。
  • 避免使用 Shell 关键字: 不要使用Shell的关键字(例如 if、then、else、fi、for、while 等)作为变量名,以免引起混淆。
  • 使用大写字母表示常量: 习惯上,常量的变量名通常使用大写字母,例如 PI=3.14。
  • 避免使用特殊符号: 尽量避免在变量名中使用特殊符号,因为它们可能与 Shell 的语法产生冲突。
  • 避免使用空格: 变量名中不应该包含空格,因为空格通常用于分隔命令和参数。

有效的 Shell 变量名示例如下:

VAR="baidu.com"
var="abc"
LD_PATH="/bin/"
_var="123"
var2="abc"

无效的变量命名:

# 避免使用if作为变量名
if="my_var"
# 避免使用 $ 等特殊符号
var_$=42
?var=123
my*var=run
my-var=123
# 避免空格
my var="abc"
# 避免以数字开头
2var="123"

等号两侧避免使用空格:

# 正确的赋值
my_var=abc
# 有可能会导致错误
my_var = abc

2)普通变量与临时环境变量区别

Shell进程的环境变量作用域是Shell进程,当export导入到系统变量时,则作用域是Shell进程及其Shell子进程。

[root@nieay ~]# ps axjf |grep pts
120425 120439 120425 120425 ?            -1 S     1000   0:00  |   \_ sshd: eliah@pts/0
120439 120443 120443 120443 pts/0    120670 Ss    1000   0:00  |       \_ -bash
120443 120614 120614 120443 pts/0    120670 S        0   0:00  |           \_ su
120614 120622 120622 120443 pts/0    120670 S        0   0:00  |               \_ bash
120622 120670 120670 120443 pts/0    120670 R+       0   0:00  |                   \_ ps axjf
120622 120671 120670 120443 pts/0    120670 S+       0   0:00  |                   \_ grep --color=auto pts
[root@nieay ~]# echo $$
120622
[root@nieay ~]# VAR=123
[root@nieay ~]# echo $VAR
123
[root@nieay ~]# bash
[root@nieay ~]# echo $$
120680
[root@nieay ~]# ps axjf |grep pts
120425 120439 120425 120425 ?            -1 S     1000   0:00  |   \_ sshd: eliah@pts/0
120439 120443 120443 120443 pts/0    120712 Ss    1000   0:00  |       \_ -bash
120443 120614 120614 120443 pts/0    120712 S        0   0:00  |           \_ su
120614 120622 120622 120443 pts/0    120712 S        0   0:00  |               \_ bash
120622 120680 120680 120443 pts/0    120712 S        0   0:00  |                   \_ bash
120680 120712 120712 120443 pts/0    120712 R+       0   0:00  |                       \_ ps axjf
120680 120713 120712 120443 pts/0    120712 S+       0   0:00  |                       \_ grep --color=auto pts
[root@nieay ~]# echo $VAR[root@nieay ~]# exit
exit
[root@nieay ~]# echo $VAR
123
[root@nieay ~]# export VAR
[root@nieay ~]# bash
[root@nieay ~]# echo $$
120722
[root@nieay ~]# ps axjf |grep pts
120425 120439 120425 120425 ?            -1 S     1000   0:00  |   \_ sshd: eliah@pts/0
120439 120443 120443 120443 pts/0    120763 Ss    1000   0:00  |       \_ -bash
120443 120614 120614 120443 pts/0    120763 S        0   0:00  |           \_ su
120614 120622 120622 120443 pts/0    120763 S        0   0:00  |               \_ bash
120622 120722 120722 120443 pts/0    120763 S        0   0:00  |                   \_ bash
120722 120763 120763 120443 pts/0    120763 R+       0   0:00  |                       \_ ps axjf
120722 120764 120763 120443 pts/0    120763 S+       0   0:00  |                       \_ grep --color=auto pts
[root@nieay ~]# echo $VAR
123
[root@nieay ~]# ps -ef |grep ssh
root       1186      1  0 10月09 ?      00:00:00 /usr/sbin/sshd -D -

ps axjf输出的第一列是PPID(父进程ID),第二列是PID(子进程ID)
当SSH连接Shell时,当前终端PPID(-bash)是sshd守护程序的PID(root@pts/0),因此在当前终端下的所有进程的PPID都是-bash的PID,比如执行命令、运行脚本。
所以当在-bash下设置的变量,只在-bash进程下有效,而-bash下的子进程bash是无效的,当export后才有效。
进一步说明:再重新连接SSH,去除上面定义的变量测试下

[root@nieay linux]# ps -axjf |grep pts2518   2574   2518   2518 ?            -1 S     1000   0:09  |   \_ sshd: eliah@pts/02574   2579   2579   2579 pts/0     28018 Ss    1000   0:00  |       \_ -bash2579   2704   2704   2579 pts/0     28018 S        0   0:00  |       |   \_ sudo su2704   2787   2704   2579 pts/0     28018 S        0   0:00  |       |       \_ su2787   2790   2790   2579 pts/0     28018 S        0   0:00  |       |           \_ bash2790  28018  28018   2579 pts/0     28018 R+       0   0:00  |       |               \_ ps -axjf2790  28019  28018   2579 pts/0     28018 S+       0   0:00  |       |               \_ grep --color=auto pts
[root@nieay linux]# echo $$
2790
[root@nieay linux]# VAR=123
[root@nieay linux]# vim test.sh
[root@nieay linux]# cat test.sh
#!/usr/bin
ps -axjf |grep pts
echo $$
echo $VAR
[root@nieay linux]# bash test.sh2518   2574   2518   2518 ?            -1 S     1000   0:09  |   \_ sshd: eliah@pts/02574   2579   2579   2579 pts/0     28901 Ss    1000   0:00  |       \_ -bash2579   2704   2704   2579 pts/0     28901 S        0   0:00  |       |   \_ sudo su2704   2787   2704   2579 pts/0     28901 S        0   0:00  |       |       \_ su2787   2790   2790   2579 pts/0     28901 S        0   0:00  |       |           \_ bash2790  28901  28901   2579 pts/0     28901 S+       0   0:00  |       |               \_ bash test.sh28901  28902  28901   2579 pts/0     28901 R+       0   0:00  |       |                   \_ ps -axjf28901  28903  28901   2579 pts/0     28901 S+       0   0:00  |       |                   \_ grep pts
28901[root@nieay linux]# export VAR
[root@nieay linux]# bash test.sh2518   2574   2518   2518 ?            -1 S     1000   0:09  |   \_ sshd: eliah@pts/02574   2579   2579   2579 pts/0     29270 Ss    1000   0:00  |       \_ -bash2579   2704   2704   2579 pts/0     29270 S        0   0:00  |       |   \_ sudo su2704   2787   2704   2579 pts/0     29270 S        0   0:00  |       |       \_ su2787   2790   2790   2579 pts/0     29270 S        0   0:00  |       |           \_ bash2790  29270  29270   2579 pts/0     29270 S+       0   0:00  |       |               \_ bash test.sh29270  29271  29270   2579 pts/0     29270 R+       0   0:00  |       |                   \_ ps -axjf29270  29272  29270   2579 pts/0     29270 S+       0   0:00  |       |                   \_ grep pts
29270
123

所以在当前shell定义的变量一定要export,否则在写脚本时,会引用不到。
还需要注意的是退出终端后,所有用户定义的变量都会清除。
在/etc/profile下定义的变量就是这个原理,后面有章节会讲解Linux常用变量文件。

3、位置变量

位置变量指的是函数或脚本后跟的第n个参数。
$1-$n,需要注意的是从第10个开始要用花括号调用,例如${10}。

变量描述
$0当前脚本的文件名
$1~$9第 1 到第 9 个参数
${n}第 n 个参数(n ≥ 10,如 ${10})

shift可对位置变量控制,例如:

[root@nieay linux]# cat test1.sh
#!/usr/bash
echo "文件名:$0"
echo "第一个参数:$1"
shift
echo "第二个参数:$2"
shift
echo "第三个参数:$3"
echo "第五个参数:${5}"
[root@nieay linux]# bash test1.sh a b c d e f g
文件名:test1.sh
第一个参数:a
第二个参数:c
第三个参数:e
第五个参数:g

每执行一次shift命令,位置变量个数就会减一,而变量值则提前一位。shift n,可设置向前移动n位。

4、特殊变量

变量描述
$0脚本自身名字
$?返回上一条命令是否执行成功,0为执行成功,非0则为执行失败
$#位置参数总数
$*所有的位置参数被看做一个字符串,如"$*“用「”」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$@每个位置参数被看做独立的字符串,如"$@“用「”」括起来的情况、以"$1" “2"…"2" … "2""n” 的形式输出所有参数。
$$当前进程PID
$!上一条运行后台进程的PID
$-显示Shell使用的当前选项,与set命令功能相同。

$*$@ 区别:

  • 相同点:都是引用所有参数。
  • 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,则 " * " 等价于 “1 2 3”(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)。

示例:

[root@nieay linux]# vim test2.sh
[root@nieay linux]# cat test2.sh
#!/bin/bash
echo "执行的文件名:$0"
echo "第一个参数为:$1"
echo "参数个数:$#"
echo "当前进程ID号:$$"
echo "上一个进程ID号:$!"
echo "所有参数 (独立): $@"
echo "所有参数 (合并): $*"for i in "$*"; doecho "\$*参数:$i"
donefor i in "$@"; doecho "\$@参数:$i"
done
echo "退出状态:$?"
[root@nieay linux]# bash test2.sh aaa bbb ccc "ab c"
执行的文件名:test2.sh
第一个参数为:aaa
参数个数:4
当前进程ID号:53331
上一个进程ID号:
所有参数 (独立): aaa bbb ccc ab c
所有参数 (合并): aaa bbb ccc ab c
$*参数:aaa bbb ccc ab c
$@参数:aaa
$@参数:bbb
$@参数:ccc
$@参数:ab c
退出状态:0

五、变量引用

赋值运算符示例
=变量赋值
+=两个变量相加

1、自定义变量及引用

[root@nieay linux]# a=123
[root@nieay linux]# echo $a
123
[root@nieay linux]# a+=123
[root@nieay linux]# echo $a
123123

Shell中所有变量引用使用$符,后跟变量名。
有时个别特殊字符会影响正常引用,那么需要使用${VAR},如:

[root@nieay linux]# a=123
[root@nieay linux]# echo $a_[root@nieay linux]# echo ${a}
123

Shell允许a_为变量名,所以此引用认为这是一个有效的变量名,故此返回空。

有时变量名与其他字符串紧碍着,也会误认为是整个变量:

[root@nieay linux]# echo $a123[root@nieay linux]# echo ${a}123
123123

2、将命令结果作为变量值

[root@nieay linux]# a='echo 123'
[root@nieay linux]# echo $a
echo 123
[root@nieay linux]# a=`echo 123`
[root@nieay linux]# echo $a
123
[root@nieay linux]# a=$(echo 123)
[root@nieay linux]# echo $a
123

这里的反撇号等效于$(),都是用于执行Shell命令。
注意:反撇号`,不是单引号

六、双引号和单引号

在变量赋值时,如果值有空格,Shell会把空格后面的字符串解释为命令:

[root@nieay linux]# a=1 2 3
bash: 2: 未找到命令...
[root@nieay linux]# a="1 2 3"
[root@nieay linux]# echo $a
1 2 3
[root@nieay linux]# a='1 2 3'
[root@nieay linux]# echo $a
1 2 3

这个看不出区别,比如:

[root@nieay linux]# b=3
[root@nieay linux]# a="1 2 $b"
[root@nieay linux]# echo $a
1 2 3
[root@nieay linux]# a='1 2 $b'
[root@nieay linux]# echo $a
1 2 $b

单引号是告诉Shell忽略特殊字符,而双引号则解释特殊符号原有的意义,比如$
单引号字符串的限制:

  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
  • 单引号字符串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。

双引号的优点:

  • 双引号里可以有变量
  • 双引号里可以出现转义字符

七、Shell注释

1、单行注释

# 开头的行就是注释,会被解释器忽略。

通过每一行加一个 # 号设置多行注释,如:

#--------------------------------------------
# 这是一个注释#--------------------------------------------
##### 用户配置区 开始 #####
#
#
# 这里可以添加脚本描述信息
#
#
##### 用户配置区 结束  #####

如果在开发过程中,遇到大段的代码需要临时注释起来,过一会儿又取消注释,怎么办呢?
每一行加个#符号太费力了,可以把这一段要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果。

2、多行注释

使用 Here 文档
多行注释还可以使用以下格式:

:<<EOF
注释内容...
注释内容...
注释内容...
EOF

: 是一个空命令,用于执行后面的 Here 文档,<<'EOF' 表示开启 Here 文档,COMMENT 是 Here 文档的标识符,在这两个标识符之间的内容都会被视为注释,不会被执行。
EOF 也可以使用其他符号:

: <<'COMMENT'
这是注释的部分。
可以有多行内容。
COMMENT:<<'
注释内容...
注释内容...
注释内容...
':<<!
注释内容...
注释内容...
注释内容...
!

直接使用 :
可以使用冒号 : 命令,并用单引号 ' 将多行内容括起来。由于冒号是一个空命令,这些内容不会被执行。
格式为:: + 空格 + 单引号

: '
这是注释的部分。
可以有多行内容。
'
http://www.dtcms.com/a/488441.html

相关文章:

  • 征婚网站开发呼市网站制作
  • 扬州西区网站建设安康手机网站建设
  • html5自适应网站模版打鱼网站怎么做
  • 新乡高端网站建设app定制开发深圳
  • [Qlib] 回测执行 | `backtest_daily`日频回测
  • 简洁商城网站模板网站终端制作
  • P11215 【MX-J8-T3】水星湖
  • 温湿度传感器技术深度解析:从测量原理到工程落地
  • 将 localhost 代理配置镜像到 WSL
  • 企业展示网站如何建wordpress 打开慢 google
  • 餐饮网站欣赏wordpress 归档页面地址
  • 网站优化目标旅游营销型网站
  • 防钓鱼网站宣传深圳网站建设与制作公司
  • 淘宝小网站怎么做的怎么把asp网站做的好看
  • 外贸网站 备案昆明网站建设案例
  • 新建网站求友链平台河南建设工程信息网查询
  • 视觉设计网站推荐中山市做网站专业的
  • 集团网站群建设方案法治建设网站模块名称
  • 聊城网站制作价格企业网站源码利于优化
  • 网站不接入备案wordpress videotheme
  • 目标检测算法
  • 辽宁省城乡建设规划院网站12380举报网站制度建设
  • 南京网站设计公司排名东营可以做网站的公司在哪
  • wordpress建群站网上销售怎么做的更好
  • html5网站布局教程一个网站的作用是什么
  • 15-K均值聚类:分析基于距离的经典聚类算法及其应用
  • 见网站建设客户技巧东莞推广系统哪里找
  • 做外贸英语要什么网站价值30万的网站建设
  • 13-哈希md5案例:My Token
  • 做淘宝保健品药品在哪个网站找素材小程序开发制作流程