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

三十分钟学会Shell(上)

Shell

img

​ Shell 本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序,是用户和Linux文件系统之间的桥梁。Shell 有自己的特殊性,就是开机立马启动,并呈现在用户面前;用户通过 Shell 来使用 Linux,不启动 Shell 的话,用户就没办法使用Linux。

1. shell的基础概念

​ Shell是一种解释性的命令行界面(CLI),它为用户提供了与操作系统内核进行交互的方式。在Linux和UNIX系统中,Shell是一种基本的用户界面工具,用于执行命令、管理文件系统、启动程序等。

​ 常见的Shell有Bourne Shell(sh)、Bash(Bourne Again SHell)、C Shell(csh)和Korn Shell(ksh)等。其中,Bash是最常用的Shell,也是许多Linux发行版的默认Shell。

以下是Shell的一些主要特点和功能:

  1. 命令执行:Shell允许用户在命令行中输入命令,并将其传递给操作系统执行。用户可以执行各种任务,如文件操作、进程管理、软件安装等。
  2. 脚本编程:Shell还提供了脚本编程的功能,用户可以编写一系列的Shell命令并保存为脚本文件。这个脚本文件可以被执行,从而自动完成一系列的操作,提高效率和自动化任务。
  3. 变量和环境:Shell中可以定义和使用变量,用于存储数据和结果。用户可以通过变量来传递参数、存储临时数据等。此外,Shell还提供了环境变量,用于存储系统级别的配置信息,如路径、用户设置等。
  4. 通配符和通道:Shell支持通配符(如*、?)来匹配文件名和路径,从而方便进行文件操作。同时,Shell还支持管道(|)操作符,允许将一个命令的输出作为另一个命令的输入,实现数据流的传递和处理。
  5. 控制结构和循环:Shell提供了条件语句(如if-else)、循环语句(如for、while)等控制结构,使得用户可以根据条件执行不同的命令块或重复执行一系列的命令。
  6. 命令历史和自动补全:Shell会保存用户输入的命令历史记录,方便用户查找和重复执行之前执行过的命令。此外,Shell还支持自动补全,当用户输入命令或文件路径时,可以通过按下Tab键来自动完成。

Shell是Linux系统中强大且灵活的工具,它为用户提供了直接与操作系统交互的方式,可以根据用户需求执行各种任务和操作。通过学习和熟悉Shell,用户可以更好地管理和控制他们的系统。

1.1 Shell分类

​ Shell 是提供与内核沟通接口的命令解释器程序,但实际上 Shell 是这种解释器的统称,Linux 系统的 Shell 种类很多,包括 Bourne Shell(简称 sh)、Bourne Again Shell(简称 bash)、C Shell(简称 csh)、K shell(简称 ksh)等等。如下图:
在这里插入图片描述

​ 也就是说 sh 和 bash 都是 Linux 系统 Shell 的一种,其中 bash 命令是 sh 命令的超集,大多数 sh 脚本都可以在 bash 下运行。Linux 系统中预设默认使用的就是 bash。

1.2 She Bang

She Bang是Shell脚本的第一行:#!/bin/bash,通常是用来指定要运行的脚本的解释器。

  • #! 就是告诉系统解释此脚本文件的 Shell 程序在哪(其后路径所指定的程序)
  • /bin/bash是解释器的路径。

所以 She Bang的格式重要,格式不正确会导致命令工作不正常。其中大家要记住的是:

  • She Bang应在脚本的第一行。
  • 在 #! 和解释器的路径之间, # 之前不应有任何空格。

1.3 运行脚本的方式

  • shbash
    • 开启一个新进程运行脚本
    • 变量不能共享
  • source.
    • 在当前进程中运行脚本(所以环境变量要使用source,不然新进程中访问不到)
    • 变量可以共享
    • .代表带路径运行
  • 带路径运行
    • 运行的脚本必须有执行权限

1.4 脚本

​ 在计算机编程中,脚本是用于适当的运行时环境的一组命令,这些命令用于自动执行任务。

我们经常说的 Shell 脚本,其实就是利用 Shell 的功能,编写能够直接运行的脚本文件。

2. Shell 基础

2.1 注释

: '这就是注释'<< EOF用分界符注释不是EOF也可以,但是EOF是规范
EOF 

2.2 变量

在Shell中,变量是用来存储数据的一种方式。它们可以是数字、字符串或任何其他类型的数据。

Shell中的变量名是以美元符号($)开头的字符串,其后跟着变量名。不能在变量名中使用空格或标点符号(除了下划线),也不能以数字开头。变量名区分大小写。

下面是一些常见的Shell变量:

  1. 环境变量:这些变量包含了有关系统和用户环境的信息。例如,PATH变量定义了Shell在哪些目录中查找可执行文件。
  2. 用户定义变量:这些变量由用户自己定义,用于存储特定的数据。例如,可以定义一个变量来存储一个目录的路径名。
  3. 位置参数变量:这些变量用于存储命令行参数。例如,$0表示命令本身的名称,$1、$2等表示命令行中的第一个、第二个参数等。
  4. 预定义变量:这些变量由Shell预先定义,用于存储有关Shell状态和配置的信息。例如,$HOME变量存储当前用户的主目录路径。

Shell中使用等号(=)来给变量赋值,例如:

MY_VAR="Hello, world!"

在Shell中,可以使用echo命令来显示变量的值,例如:

echo $MY_VAR

输出结果为:

Hello, world!

可以使用unset命令来删除一个变量,例如:

unset MY_VAR

以上就是Shell中的变量的基本知识。掌握了变量的使用方法,可以更加灵活地编写Shell脚本。

2.3 引号

在Shell中,引号用于将字符串括起来。引号可以是单引号、双引号或反引号。

  1. 单引号:单引号内的所有字符都被视为普通字符,也可以原样输出,包括变量和命令替换。例如:
echo 'Hello $USER'

输出结果为:

Hello $USER
  1. 双引号:双引号内的变量和命令将会被展开。例如:
echo "Hello $USER"

输出结果为:

Hello username
  1. 反引号:反引号用于执行命令并将其输出作为字符串。例如:
echo "The date is `date`"

输出结果为:

The date is Wed Nov 24 04:27:38 UTC 2021

需要注意的是,在使用双引号时,如果想要将某些特殊字符视为普通字符而不进行转义,可以使用反斜杠(\)对其进行转义。例如:

echo "Hello \$USER"

输出结果为:

Hello $USER

在一些情况下,引号的使用可以影响变量的展开和命令的执行结果。因此,在编写Shell脚本时,需要根据具体情况来选择合适的引号。

2.4 位置参数

Shell中的位置参数指的是命令行上给定的参数,它们按照出现的顺序被依次编号为$1、$2等。其中,$0表示命令本身的名称。

例如,假设有一个名为test.sh的脚本,可以这样在命令行上给其传递参数:

./test.sh arg1 arg2 arg3

在test.sh脚本中,可以使用位置参数来获取这些参数值:

echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "第三个参数为:$3"

输出结果为:

第一个参数为:arg1
第二个参数为:arg2
第三个参数为:arg3

如果需要获取所有的位置参数,可以使用 @ 或 @或 @*来表示。这两个变量都表示所有的位置参数,不同之处在于如果将它们放在引号内, ∗ 会将所有参数解释成一个字符串,而 *会将所有参数解释成一个字符串,而 会将所有参数解释成一个字符串,而@则会将每个参数解释成一个独立的字符串。

例如:

#!/bin/bash
echo "所有的参数为:$*"
echo "所有的参数为:$@"

执行命令:

./test.sh arg1 arg2 arg3

输出结果为:

所有的参数为:arg1 arg2 arg3
所有的参数为:arg1 arg2 arg3

需要注意的是,如果参数中包含空格等特殊字符,需要用引号将其括起来以避免解释错误。例如:

./test.sh "arg1 with space" arg2 "arg3 with space"

在脚本中使用位置参数时,也可以通过shift命令将参数左移一位,以便获取下一个参数。例如:

#!/bin/bash
echo "第一个参数为:$1"
shift
echo "第二个参数为:$1"

执行命令:

./test.sh arg1 arg2 arg3

输出结果为:

第一个参数为:arg1
第二个参数为:arg2

这就是Shell中的位置参数。通过它们,可以让Shell脚本处理多个参数,并根据具体需求对其进行处理。

2.5 特殊变量

Shell中有一些特殊变量,它们具有特定的含义和功能。以下是一些常见的Shell特殊变量:

在这里插入图片描述

  1. $0

这个变量保存了当前脚本或命令的名称。例如,在一个名为myscript.sh的Shell脚本中,$0将会是myscript.sh

#!/bin/bashecho "The name of this script is: $0"

执行上述脚本,输出结果为:

The name of this script is: myscript.sh
  1. $1, $2, …

这些变量用来表示位置参数,即命令行上给定的参数。例如,在执行脚本时,可以使用$1来获取第一个参数,使用$2来获取第二个参数,以此类推。

#!/bin/bashecho "The first argument is: $1"
echo "The second argument is: $2"

执行上述脚本并传递两个参数,输出结果为:

The first argument is: arg1
The second argument is: arg2
  1. $@

这个变量表示所有的位置参数。它将所有传递给脚本或命令的参数看作一个整体,可以使用循环来遍历所有参数。

#!/bin/bashecho "All arguments are: $@"

执行上述脚本并传递三个参数,输出结果为:

All arguments are: arg1 arg2 arg3

可以将$@用于循环中,以便遍历所有位置参数:

#!/bin/bashfor arg in "$@"
doecho "Argument: $arg"
done

执行上述脚本并传递三个参数,输出结果为:

Argument: arg1
Argument: arg2
Argument: arg3
  1. $#

这个变量表示位置参数的个数,不包括脚本或命令本身的名称。

#!/bin/bashecho "The number of arguments is: $#"

执行上述脚本并传递三个参数,输出结果为:

The number of arguments is: 3
  1. $?

这个变量表示上一个命令的退出状态码。如果命令执行成功,则其值为0;如果命令执行失败,则其值为非零。

#!/bin/bashls /notexist
echo "The exit status of the previous command is: $?"

执行上述脚本,由于ls /notexist命令找不到指定目录,其退出状态码为1,因此输出结果为:

ls: cannot access '/notexist': No such file or directory
The exit status of the previous command is: 1
  1. $$

这个变量表示当前脚本或命令的进程ID(PID)。它在脚本中可以用来标识当前进程的唯一性。

#!/bin/bashecho "The PID of this script is: $$"

执行上述脚本,输出结果为:

The PID of this script is: 1234
  1. $!

这个变量表示最后一个在后台运行的命令的进程ID。可以用来获取最后一个后台任务的PID。

#!/bin/bashsleep 5 &
echo "The PID of the last background command is: $!"

执行上述脚本,由于sleep 5 &命令被放到后台运行,其PID为1234,因此输出结果为:

The PID of the last background command is: 1234
  1. $*

这个变量表示所有的位置参数作为单个字符串。它将所有参数解释成一个字符串,而不是一个数组。可以使用引号将其括起来,以保留参数之间的空格。

#!/bin/bashecho "All arguments as a single string: $*"

执行上述脚本并传递三个参数,输出结果为:

All arguments as a single string: arg1 arg2 arg3
  1. $IFS

这个变量表示内部字段分隔符(Internal Field Separator)。它定义了Shell将输入拆分成字段(或单词)的分隔符,默认情况下,它包含空格、制表符和换行符。

#!/bin/bashecho "The default value of IFS is: '$IFS'"IFS=":"
echo "After changing IFS to ':', it is: '$IFS'"

执行上述脚本,输出结果为:

The default value of IFS is: ' 	
'
After changing IFS to ':', it is: ':'
  1. $HOME

这个变量表示当前用户的主目录。

#!/bin/bashecho "The home directory of the current user is: $HOME"

执行上述脚本,输出结果为:

The home directory of the current user is: /home/user
  1. $PWD

这个变量表示当前工作目录的路径。

#!/bin/bashecho "The current working directory is: $PWD"

执行上述脚本,输出结果为:

The current working directory is: /home/user

这些特殊变量可以在Shell脚本中使用,让你可以获取和处理各种信息,以及控制脚本的行为。通过利用这些变量,你可以编写更灵活、可配置的Shell脚本。

2.6 字符串

在Shell编程中,字符串是一个由字符组成的序列。Shell提供了多种方式来处理字符串,包括字符串拼接、提取子串、替换等操作。

  1. 字符串的定义

    • 单引号:使用单引号'可以定义一个单行字符串,其中的内容会被原样输出,不会进行变量替换和转义字符的解释。

      str='Hello, World!'
      
    • 双引号:使用双引号"可以定义一个单行字符串,其中的内容可以包含变量、转义字符和命令替换。

      name='Alice'
      str="Hello, $name!"
      
    • Here文档:使用Here文档可以定义包含多行内容的字符串,可以使用任意的定界符。

      str=$(cat <<EOF
      Hello,
      World!
      EOF
      )
      
  2. 字符串拼接
    使用连接操作符.可以将两个字符串拼接在一起。

    str1='Hello,'
    str2=' World!'
    result=$str1$str2
    echo $result  # 输出:Hello, World!
    
  3. 字符串长度
    使用${#string}可以获取字符串的长度。

    str='Hello, World!'
    len=${#str}
    echo $len  # 输出:13
    
  4. 子串提取

    • 从左边开始提取指定长度的子串:${string:start:length}

      str='Hello, World!'
      sub=${str:0:5}
      echo $sub  # 输出:Hello
      
    • 从右边开始提取指定长度的子串:${string:start-length}

      str='Hello, World!'
      sub=${str:7-5:5}
      echo $sub  # 输出:World
      
  5. 字符串替换

    • 替换第一个匹配的子串:${string/substring/replacement}

      str='Hello, World!'
      new_str=${str/World/China}
      echo $new_str  # 输出:Hello, China!
      
    • 替换所有匹配的子串:${string//substring/replacement}

      str='Hello, World!'
      new_str=${str//o/O}
      echo $new_str  # 输出:HellO, WOrld!
      
  6. 字符串切割为数组
    使用IFS(内部字段分隔符)将字符串切割为数组。

    str='apple,banana,cherry'
    IFS=',' read -ra arr <<< "$str"
    echo ${arr[1]}  # 输出:banana
    
  7. 字符串比较
    使用=!=><等符号进行字符串比较。

    str1='apple'
    str2='banana'
    if [[ $str1 == $str2 ]]; thenecho 'Equal'
    elseecho 'Not equal'  # 输出:Not equal
    fi
    
  8. 在Shell中,#*%*是用于字符串处理的特殊符号,用于匹配和删除字符串中的特定模式。

    1. #*

      • 语法:${variable#*pattern}

      • 功能:从变量${variable}的开头开始,删除第一个匹配pattern的字符串及其左边的内容,返回剩余的部分。

      • 示例:

        str="Hello, World!"
        echo ${str#*o}  # 输出:llo, World!
        

      在这个示例中,${str#*o}会删除str变量中第一个匹配字母o及其左边的所有字符,返回剩余的部分llo, World!

    2. %*

      • 语法:${variable%pattern*}

      • 功能:从变量${variable}的结尾开始,删除最后一个匹配pattern的字符串及其右边的内容,返回剩余的部分。

      • 示例:

        str="Hello, World!"
        echo ${str%o*}  # 输出:Hello, W
        

      在这个示例中,${str%o*}会删除str变量中最后一个匹配字母o及其右边的所有字符,返回剩余的部分Hello, W

这些是Shell中处理字符串的一些常用操作和技巧。通过灵活运用这些操作,可以对字符串进行各种处理和转换,从而实现复杂的逻辑和功能。

2.7 数组

在Shell脚本中,数组是一种特殊的变量类型,用于存储一组相关的值。Shell支持一维数组,即只能存储一列值。

  1. 声明数组:

    • 语法:array_name=(value1 value2 ... valuen)

    • 示例:

      fruits=("apple" "banana" "orange")
      

    在这个示例中,我们声明了一个名为fruits的数组,并初始化了三个元素"apple""banana""orange"

  2. 读取数组元素:

    • 语法:${array_name[index]}

    • 示例:

      echo ${fruits[0]}  # 输出:apple
      

    数组元素可以通过索引(从0开始)来访问。${fruits[0]}表示fruits数组中的第一个元素。

  3. 修改数组元素:

    • 语法:array_name[index]=new_value

    • 示例:

      fruits[1]="grape"
      echo ${fruits[1]}  # 输出:grape
      

    fruits[1]="grape"fruits数组中索引为1的元素修改为"grape"

  4. 获取数组长度:

    • 语法:${#array_name[@]}

    • 示例:

      length=${#fruits[@]}
      echo $length  # 输出:3
      

    ${#fruits[@]}返回fruits数组的长度,即元素的个数。

  5. 遍历数组:

    • 示例:

      for fruit in ${fruits[@]}; doecho $fruit
      done
      

    这个示例中,通过for循环遍历fruits数组的所有元素,并逐个输出。

  6. 添加新元素到数组:

    • 示例:

      shell复制代码fruits+=("pear")
      echo ${fruits[@]}  # 输出:apple banana orange grape pear
      

    通过使用+=操作符,可以向数组末尾添加新的元素。

  7. 删除数组元素:

    • 示例:

      shell复制代码unset fruits[1]
      echo ${fruits[@]}  # 输出:apple orange grape
      

​ 使用unset命令可以删除数组中指定索引位置的元素。

  1. 切片数组:

    • 示例:

      shell复制代码echo ${fruits[@]:1:2}  # 输出:orange grape
      

${fruits[@]:1:2}表示从索引为1的位置开始,取2个元素,形成切片数组。

数组在Shell脚本中用于存储多个相关的值,可以方便地进行数据的组织和处理。通过索引访问、修改元素,获取数组长度以及遍历数组等操作,可以灵活地操作和处理数组中的数据。

相关文章:

  • 51单片机的智能浇花系统【含proteus仿真+程序+报告+原理图】
  • vue3的 nextTick()的使用
  • leetcode 240. 搜索二维矩阵 II
  • [Android]使用Retrofit进行网络请求
  • 含分布式电源的配电网可靠性评估(matlab代码)
  • vue2.0+elementui集成file-loader之后图标失效问题
  • 安徽省广德市选择云轴科技ZStack Cloud云平台建设县级智慧城市
  • SQL注入漏洞发现和利用,以及SQL注入的防护
  • 【精选】Ajax技术知识点合集
  • centos7 系统keepalived 定时执行脚本
  • 百度智能云正式上线Python SDK版本并全面开源
  • SQL Server数据库自动备份方法
  • 机器学习第12天:聚类
  • python二叉树链树_树的链式存储结构
  • yum仓库
  • Angular数据绑定机制
  • CentOS从零开始部署Nodejs项目
  • co模块的前端实现
  • Hibernate【inverse和cascade属性】知识要点
  • Hibernate最全面试题
  • JAVA SE 6 GC调优笔记
  • js继承的实现方法
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • Mysql优化
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 多线程 start 和 run 方法到底有什么区别?
  • 回流、重绘及其优化
  • 技术胖1-4季视频复习— (看视频笔记)
  • 力扣(LeetCode)56
  • 前端学习笔记之原型——一张图说明`prototype`和`__proto__`的区别
  • 强力优化Rancher k8s中国区的使用体验
  • 入门到放弃node系列之Hello Word篇
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 用element的upload组件实现多图片上传和压缩
  • 最简单的无缝轮播
  • 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler ...
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • 通过调用文摘列表API获取文摘
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • #Spring-boot高级
  • $(function(){})与(function($){....})(jQuery)的区别
  • (Python) SOAP Web Service (HTTP POST)
  • (第61天)多租户架构(CDB/PDB)
  • (二)学习JVM —— 垃圾回收机制
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (接口自动化)Python3操作MySQL数据库
  • (算法)Travel Information Center
  • (一)RocketMQ初步认识
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .bat批处理(一):@echo off
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .Net(C#)自定义WinForm控件之小结篇