查看原文
其他

【10-1】做数据分析,要不要掌握Linux系列:shell编程之变量!

黄伟呢 数据分析与统计学之美 2023-05-04

1、shell的介绍

1)什么是shell?

Shell 本身是一个用c语言编写的程序,它是用户使用Unix/Linux的桥梁,用户的大部分工作都是通过Shell完成的。
Shell 既是一种命令语言,又是一种程序设计语言:作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。
Shell 它虽然不是Unix/Linux系统内核的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。Shell 是用户与内核进行交互操作的一种接口,目前最流行的Shell称为bash Shell(Bourne Again Shell)。
Shell是一门编程语言(解释型的编程语言,即shell脚本(就是在用linux的shell命令编程),Shell 脚本程序从脚本中一行一行读取并执行这些命令,相当于一个用户把脚本中的命令一行一行敲到Shell提示符下执行。
Shell是一种脚本语言,那么,就必须有解释器来执行这些脚本。Unix/Linux上常见的shell脚本解释器有bash、sh、csh、ksh等,习惯上把它们称作一种Shell。
我们常说有多少种Shell,其实说的是Shell脚本解释器,可以通过cat   /etc/shells命令查看系统中安装的shell,不同的shell可能支持的命令语法是不相同的。
sh是Unix标准默认的shell,由Steve Bourne 开发,是Bourne Shell的缩写。
bash是Linux标准默认的shell,由Brian Fox 和Chet Ramey共同完成,是Bourne Again Shell的缩写。
shell本身支持的命令并不多,内部命令一共有40个,但是它可以调用其他的程序,每个程序就是一个命令,这使得Shell命令的数量可以无限扩展,其结果就是Shell的功能非常强大,完全能够胜任Linux的日常管理工作,如文本或字符串检索、文件的查找或创建、大规模软件的自动部署、更改系统设置、监控服务器性能、发送报警邮件、抓取网页内容、压缩文件等。
# 查看系统中安装的shell
[hadoop@image_boundary ~]$ cat /etc/shells 
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash

2、shell语言

shell脚本代码通常写在普通文本文件中,通常以.sh结尾,虽然不是强制要求,但希望大家最好这么做

1)基本语法

// vim是创建并打开了一个文件。
// a.sh存在,就是打开该文件;
// a.sh不存在,就是创建该文件。
[root@image_boundary ~]# vim a.sh
上述命令:创建并打开了a.sh这个文件。
我们在该脚本中写入如下两行代码。
//  一般在一个shell脚本的首行需要输入【#!/bin/bash】这句代码。
// 【#!/bin/bash】表示设置默认解释器类型。
// 但是如果【指定解释器执行】该脚本时,该行无效。
#!/bin/bash    
echo "Hello World"   

2)shell脚本的3种执行方式:大前提,都必须是在shell脚本所在目录下执行。

Ⅰ   指定解释器执行:【sh/bash + 脚本名称】。
操作如下:
[root@image_boundary ~]# sh a.sh
Hello World
[root@image_boundary ~]# bash a.sh
Hello World
Ⅱ   bash内部命令:【source + 脚本名称】或【. + 脚本名称】。
操作如下:
[root@bigdata111 ~]# source a.sh
aa
[root@bigdata111 ~]# . a.sh
aa
  • 注意1:source命令也称为“点命令”也就是一个点符号(.),是bash的内部命令。
  • 注意2:source命令通常用于重新执行刚修改的初始化文件,使之立即生效,而不必注销并重新登录。
  • 注意3:.和脚本名称之间是有空格的。
Ⅲ   直接执行:赋予文件可执行权限,才可以执行。
# 1 先确保该shell脚本文件有执权限
# chmod命令可以修改可读、可写、可执行的权限
chmod    

# 2 相对路径执行法(每次执行,必须切换到文件所在目录)
# 这里的点(.)指的是“当前路径”。
./脚本文件名

# 3 绝对路径执行法(只要有权限,什么路径下都可以执行)
/root/脚本文件名
操作如下:
// 修改该文件的权限,使其具有可执行的权限。
[root@image_boundary ~]# chmod 744 a.sh
[root@image_boundary ~]# ll
total 4
-rwxr--r--. 1 root root 31 Oct 18 09:18 a.sh

// 相对路径执行:必须切换到该文件的目录当中去,才可以执行。
[root@image_boundary ~]# ./a.sh
Hello World

// 绝对路径执行:在任何地方都可以执行。
[root@image_boundary ~]# /root/a.sh
Hello World
Ⅳ   这三种执行shell脚本命令的异同

3)shell脚本中【注释】的写法

3、变量

1)系统变量

// set:查看所有系统变量
[root@image_boundary ~]# set

// 常用的系统变量:$PWD   $PATH   $SHELL   $USER   $HOME
系统变量可以通过set命令查看,用户环境变量可以通过env查看。
// echo $PATH :查看Linux中配置过的环境变量
[root@image_boundary ~]# echo $PATH
/usr/local/tomcat/apache-tomcat-8.5.45/bin:/usr/local/java/jdk1.8.0_73/bin:/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

// echo $PWD :显示当前位置的绝对路径
[root@image_boundary ~]# echo $PWD
/root

// echo $USER : 显示当前你是哪一个用户登陆的虚拟机
[root@image_boundary ~]# echo $USER
root
[huangwei@image_boundary root]$ echo $USER
huangwei

// echo $HOME : 显示用户的家目录
[root@image_boundary ~]# echo $HOME
/root
[huangwei@image_boundary root]$ echo $HOME
/home/huangwei

// echo $SHELL : 显示linux系统默认的shell
[root@image_boundary ~]# echo $SHELL
/bin/bash

2)定义变量

语法格式:变量名=值

注意1:在shell脚本中定义变量,等号两侧,绝对不能有空格;
注意2:值中有空格,需要使用引号;
注意3:单引号会内容脱意,双引号可以识别变量;
注意4:变量紧挨着其它单词,可以使用${A}来获取变量A的值;
// shell中定义变量,等号两侧绝对不能有空格;
[root@bigdata111 ~]# A = 12
bash: A: command not found
[root@bigdata111 ~]# A=12
// 使用$号,可以获取变量的值;
[root@bigdata111 ~]# echo $A
12
[root@bigdata111 ~]# A=abc
[root@bigdata111 ~]# echo $A
abc
[root@bigdata111 ~]# A="abc"
[root@bigdata111 ~]# echo $A
abc
// 值中用空格,值需要使用引号引起来;
[root@bigdata111 ~]# A=ab c       
-bash: c: command not found
[root@bigdata111 ~]# A="ab c"   
[root@bigdata111 ~]# echo $A
ab c
[root@bigdata111 ~]# A="Chen Li"
[root@bigdata111 ~]# B='I love $A' 
// 单引号会导致内容脱意,双引号可以识别变量;
[root@bigdata111 ~]# echo $B
I love $A
[root@bigdata111 ~]# B="I love $A"
[root@bigdata111 ~]# echo $B
I love Chen Li
// 变量紧挨其它单词,会导致$C无法正常取值;
[root@bigdata111 ~]# C="dog"
[root@bigdata111 ~]# D="Those are $Cs"
[root@bigdata111 ~]# echo $D
This are
// 想要变量与其它单词区分,可以使用${C};
[root@bigdata111 ~]# D="Those are ${C}s" 
[root@bigdata111 ~]# echo $D
Those are dogs

// 注意以下几种写法的不同点;
[root@image_boundary ~]# A="Dog"
// a放在$A前面:a$A
[root@image_boundary ~]# B="Those are a$A"  
// a放在$A后面:$Aa;
[root@image_boundary ~]# C="Those are $Aa"   
[root@image_boundary ~]# echo $B
Those are aDog
[root@image_boundary ~]# echo $C
Those are

3)其他用法

1)撤销变量:unset 变量名;
2)设置只读变量:readonly 变量名=值;
   注意:设置只读变量后,修改、撤销只读变量,会报错。
① 撤销变量操作如下:
[root@image_boundary ~]# A=12
[root@image_boundary ~]# echo $A
12
// 撤销变量后,变量输出为空;
[root@image_boundary ~]# unset A   
[root@image_boundary ~]# echo $A

[root@image_boundary ~]#
② 设置只读变量操作如下:
[root@image_boundary ~]# readonly A=100
// 修改只读变量,会报错;
[root@image_boundary ~]# A=666    
-bash: A: readonly variable
// 撤销只读变量,会报错;
[root@image_boundary ~]# unset A  
-bash: unset: A: cannot unset: readonly variable

4、案例:变量的使用(有意思的案例)

1)绝对路径执行:才会有父进程、子进程

写两个脚本,在a.sh中调用b.sh执行,那我们想知道a脚本能不能获取到b脚本的变量,同时b脚本能不能获取到a脚本的变量?
// 脚本a.sh中的内容;
#!/bin/bash 
A="A in a.sh"
echo $A
echo $B
/root/b. sh

// 脚本b.sh中的内容;
#!/bin/bash 
B="B in b. sh"
echo $B
echo $A
使用cat命令分别查看这两个脚本文件中的内容。
① 先创建a.sh和b.sh文件,查看其权限:没有可执行的权限。
② 使用chmod命令修改权限。
[root@bigdata111 ~]# chmod 755 a.sh
[root@bigdata111 ~]# chmod 755 b.sh
可以看到,a.sh和b.sh都有了可执行权限。
③ 执行a.sh这个脚本文件。
[root@bigdata111 ~]# sh a.sh
结果如下:
分析: 为什么a.sh中【echo A】没有执行?
shell是一个脚本程序,对于脚本程序,都是从脚本中一行一行读取并执行这些命令。因此,第一个【echo A】为 什么也为空,分析如图所示。
把A、B两个变量提升为全局变量!会出现什么结果呢?
注意:上图中,假如把A和B同时提升为“全局变量”,但是子进程b.sh可以使用父进程中的A变量,而父进程a.sh却不能使用子进程的B变量。

2)内部命令执行:根本就没有父进程和子进程这一说,都是同一个进程。

因此在a.sh中可以使用b.sh中的变量B;在b.sh中可以使用a.sh中的变量A。

为了更好地说明上述区别,我们在脚本中分别打印$$,显示进程数。

// $$:显示进程数
[root@image_boundary ~]# echo $$
9544
第一种情况,使用“绝对路径调用方式”:
第二种情况,使用“内部命令调用方式”:
总结如下:

5、变量中几个常用符号

1)反引号``和$():先计算再赋值

反引号``:键盘上Tab键上方的一个键,和~在一个格子上。
操作如下:
[root@bigdata111 ~]# A=`date`
[root@bigdata111 ~]# echo $A
Mon Sep 30 06:20:02 CST 2019
// $(变量):表示先计算,再赋值;
[root@bigdata111 ~]# B=$(date)
[root@bigdata111 ~]# echo $B
Mon Sep 30 06:20:36 CST 2019

// 练习:你可以尝试以下以下操作,看看结果是什么?
[root@bigdata111 ~]# ll
total 8
-rw-r--r--. 1 root root  390 Oct  2 01:04 a.txt
-rw-r--r--. 1 root root    0 Oct  2 01:03 b.txt
drwxr-xr-x. 2 root root 4096 Oct  2 01:04 study
[root@bigdata111 ~]# echo `ll`     //  这个结果是什么
[root@bigdata111 ~]# echo $(ll)    //  这个结果是什么

2)变量中有用的技巧

${var}:获取变量本来的值;变量存在,输出原有值;变量不存在,输出空。
${var:-word}:判断某个变量是否存在。
              变量存在且有值,输出变量var的值;
              变量不存在,输出word。
               
${var:+word}:判断某个变量是否存在。
              变量存在且有值,输出word;
              变量不存在,输出为空。
             
${var:=word}:变量存在,返回变量var的值;
              变量不存在,相当于创建一个新变量var,并赋值为word。
             
${var:?message}:变量存在,输出变量var的值;
                 变量不存在,报错误。

3)特殊变量:在测试的时候很常用!!!

// 0代表上一次正确执行,正数代表上一次未正确执行;
$?表示上一个命令退出的状态码;

$$ 表示当前进程编号;
$0 表示当前脚本名称;
$n 表示n位置的输入参数(n代表数字,n>=1);
$# 表示获取参数的个数,常用于循环;
$*和$@都表示获取参数列表。
操作如下:
[root@bigdata111 ~]# vim uni_var.sh
[root@bigdata111 ~]# cat uni_var.sh
#!/bin/bash
echo $?     #表示上一个命令退出的状态码
echo $$     #表示当前的进程编号
echo $0     #表示当前的脚本名称
echo $1     #表示第1个位置参数
echo $2     #表示第2个位置参数
echo $3     #表示第3个位置参数
echo $#    #表示参数的个数
echo $@    #输出参数列表
echo $*    #输出参数列表
[root@bigdata111 ~]# sh uni_var.sh aa bb cc
0
4192
uni_var.sh
aa
bb
cc
3
aa bb cc
aa bb cc
$*和$@都表示输出参数列表,区别如下:
操作如下:
结果如下:

----------End----------

为了公平起见,黄同学选择在朋友圈赠书,同时已经送了好多本书籍了。好处:这样一来,大家中奖概率也大,都会有机会的,很多都是刚刚加了我的好友,都中奖了!

方式一:复制我微信号aili1127421544,添加我微信;

方式二:长按扫描下方二维码,添加我微信;

备注:黄同学朋友圈福利多多,欢迎查阅!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存