Shell脚本基础教程

news2024/9/20 16:40:49

在这里插入图片描述

Shell脚本基础教程

Shell参数定义

定义变量

想要定义变量,只需要使用如下命令即可。

variable_name=variable_value

variable_name表示变量名,variable_value表示变量值。注意,等号与变量名和变量值之间不能有空格

变量名的命名需要遵循如下规则:

  1. 变量名的组成只能是英文字母、数字和下划线
  2. 首字母只能是英文字母和下划线,不能是数字

正确示例:

test="test"
_test=123

错误示例:

1test="test"
test%test=123
test = "test"

使用变量

定义了变量,就要使用变量。使用变量的时候,需要在变量名称前加上符号$

# 定义变量
test="hello world"

# echo是用于字符串输出的命令,这里将变量test输出到控制台
echo $test
echo ${test}!
# 输出结果
hello world
hello world!

由上面的示例,我们看到了变量名外面的花括号是可选的,加花括号是为了帮助识别变量的边界。

推荐给所有变量加上花括号,这是个好的编程习惯。

修改变量

定义的变量是可以修改的,再设置变量的值即可。

# 设置变量test的值为hello world,并打印
test="hello world"
echo ${test}

# 修改变量test的值为hello shell,并打印
test="hello shell"
echo ${test}
# 输出结果
hello world
hello shell

只读变量

使用readonly命令可以将变量定义为只读变量,只读变量的值不能被改变。

# 定义一个变量test
test="222"

# 设置test变量为只读
readonly test

# 修改test变量值为111,修改失败
test="111"
# 输出
test: readonly variable

提示信息告诉,test变量是一个只读的变量,不允许修改。

删除变量

使用unset命令可以删除变量。

# 定一个一个变量test,并打印
test="222"
echo "test的值为:$test"

# 删除变量test,再打印,发现没有了
unset test
echo "test的值为:$test"
# 输出
test的值为:222
test的值为:

刚才我们说使用readonly命令可以将变量定义为只读变量,那只读变量是否允许删除呢?

# 定一个一个变量test,并打印
test="222"
echo "test的值为:$test"

# 设置变量test为只读
readonly test

# 删除变量test,再打印,发现还有,说明没有删除成功
unset test
echo "test的值为:$test"
# 输出
test的值为:222
./test.sh: line 6: unset: test: cannot unset: readonly variable
test的值为:222

根据输出,我们发现了,只读变量是不允许删除的

变量的作用域

变量的作用域也就是变量可以使用的范围。根据变量的作用域,可以将变量分为三种。

  • 局部变量
  • 全局变量
  • 环境变量

局部变量

有的变量只能在函数内部使用,这叫做局部变量。

为了演示局部变量,使用了Shell函数的概念,若不清楚,可点击跳转先学习下函数。

# 定义了一个名为hello的函数
function hello()
{
        local name="Shell"
        echo "函数内获取:$name"
}

# 调用hello函数
hello

echo "函数外获取变量:$name"
# 输出
$ sh variables-scope.sh
函数内获取:Shell
函数外获取变量:

通过输出我们可以看到,使用了local定义的变量成为了局部变量,在函数内可以获取到此变量,但是在函数外获取不到这个变量。

全局变量

全局变量是指在当前的整个Shell进程中都有效的变量。每个Shell进程都有自己的作用域,彼此之间互不影响。在Shell脚本中定义的变量,默认就是全局变量。

#!/bin/bash

# 在脚本中定义了一个变量name,这个变量默认就是全局变量,在整个shell脚本中都可以访问
name="shell"

# 函数内获取变量
function printName()
{
        echo "函数内获取名字为:$name"
}

# 函数外获取变量
echo "函数外获取姓名为:$name"
printName
# 输出
$ sh variables.sh
函数外获取姓名为:shell
函数内获取名字为:shell

由此可以知道,当我们直接定义一个变量的时候,默认是全局变量,整个shell脚本中都可以访问。

环境变量

全局变量只在当前 Shell 进程中有效,对其它 Shell 进程和子进程都无效。我们可以使用export命令,将变量转变为环境变量,这样Shell子进程中就可以访问到Shell父进程的变量了。当然两个没有父子关系的 Shell 进程是不能传递环境变量的。

# 以下操作在命令行中直接进行,才可以看到输出结果
name="shell"
echo "父进行中访问姓名为:$name"

bash
echo "子进程中访问姓名为:$name"

exit

export name
bash
echo "子进程中访问姓名为:$name"

age=20
echo "子进程中访问年龄为:$age"
export age
exit

echo "父进程中访问年龄为:$age"
# 输出
父进行中访问姓名为:shell
子进程中访问姓名为:
子进程中访问姓名为:shell
子进程中访问年龄为:20
父进程中访问年龄为:

由输出结果可以看出,使用export命令之后,子进程中已经可以获取到name变量了。但是子进程export的变量,父进程也是访问不到的。

变量的类型

字符串

字符串是shell编程中最常用最有用的数据类型。字符串可以用单引号,也可以用双引号,也可以不用引号。

  • 单引号:任何字符都会原样输出,单引号字符串中的变量是无效的
  • 双引号:双引号里可以有变量,双引号里可以出现转义字符

字符串还有一些常用的操作,请继续学习。

获取字符串长度
# 定义一个字符串变量,并输出字符串的长度
str="Hello World!"
echo 字符串的长度为:${#str}
# 输出
字符串的长度为:12

我们知道${variable_name}便是使用一个变量,由上面的例子,我们知道了,在变量名之前,加上#符号即${#variable_name},便可获取字符串变量的长度。

获取子字符串
str="Hello World!"
echo 位置1之后的5位字符串为:${str:0:5}
# 输出
位置1之后的5位字符串为:Hello

${variable_name:index:length}在变量名后加上子字符串开始的位置以及长度,即可获取子字符串。这里需要注意的是,索引位置是以0开始,所以index为0表示第一个字符。

查找子字符串位置
str="Hello World!"
echo o字符在字符${str}上的位置为:`expr index "${str}" o`
# 输出
o字符在字符Hello World!上的位置为:5

括住expr index "${str}" o的是反引号,表示要执行里面的内容,这里需要注意。

这里使用了expr命令来取得子字符串的位置。expr index $string $substring表示要在字符串string中找到字符串substring的位置。

更多expr命令的用法读者可以继续深入了解。

数组

定义数组

想要定义数组,可以用括号来表示数组,数组元素用"空格"符号分割。

array_name=(value0 value1 value2 value3)

或者

array_name=(
value0
value1
value2
value3
)
读取数组内元素

想要读取数组,可以使用如下命令:

# 获取数组array_name的索引index的元素
${array_name[index]}

# 获取数组array_name的索引index的元素,并赋值给value
value=${array_name[index]}

# 获取数组中的所有元素
${array_name[@]}

使用示例如下:

arr=("张三" "李四" "王五")

value=${arr[0]}
echo $value
# 输出
张三
获取数组长度

获取数组长度的方法与获取字符串长度的方法类似。

${#array_name[@]}

Shell注释

单行注释

#开头的行就是注释。就像下面这样:

#--------------------------------------------
# 这是一行注释
#--------------------------------------------

多行注释

:<<EOF开头,EOF结尾的便是多行注释。其中EOF可以替换成其他的字符,下面是两个多行注释的例子

:<<EOF
第一行注释
第二行注释
第三行注释
EOF

:<<HAHA
第一行注释
第二行注释
第三行注释
HAHA

Shell流程控制

分支语句

if else语句

if语句的语法如下:

if condition
then
    command1 
    command2
    ...
    commandN 
fi

也可以写成一行,关键点在于使用分号;作为语句的分割

if condition; then command; fi

意思是:如果condition语句成立,则执行then之后的语句,直到出现fi

使用示例演示下if语句的使用。

# 使用test命令判断脚本输入第一个参数和第二个参数的字符是否相等
if test $1 = $2
then
        echo "相等"
fi

if test $1 != $2
then
        echo "不相等"
fi
$ sh test.sh aaa aaa
相等

$ sh test.sh aaa zzz
不相等
# 将if语句写成一行
$ if test 1 -eq 1;then echo "相等";fi
相等

if else 语法`格式:

if condition
then
    command1 
    command2
    ...
    commandN
else
    command
fi

意思是:如果condition语句成立,则执行then之后的语句。若是不成立,则执行else之后的语句,直到出现fi

使用示例演示如下所示:

# 使用test命令判断脚本输入第一个参数指定的文件是否存在
if test -e $1
then
        echo "文件存在"
else
        echo "文件不存在"
fi
# 输出
$ sh test.sh "test.sh"
文件存在

$ sh test.sh "test.sh1"
文件不存在

if else-if else 语法格式:

if condition1
then
    command1
elif condition2 
then 
    command2
else
    commandN
fi

意思是:如果condition1语句成立,则执行then之后的语句。若是不成立,则继续判断condition2是否成立,若成立,则执行then之后的语句。若还是不成立,则执行else之后的语句,直到出现fi

使用示例演示如下所示:

# 使用test命令判断脚本输入第一个参数和第二个参数的大小比较
if test $1 -eq $2
then
        echo "数值相等"
elif test $1 -gt $2
then
        echo "$1大于$2"
else
        echo "${1}小于${2}"
fi
# 输出
$ sh test.sh 10 10
数值相等

$ sh test.sh 10 11
10小于11

$ sh test.sh 12 11
12大于11

case语句

case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。

case语句格式如下:

casein
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
esac

模式取值可以为变量或常数,每一模式必须以右括号结束。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;

取值将检测匹配的每一个模式。

一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。

循环语句

for循环

for循环语句格式为:

for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done

也可以写成一行

for var in item1 item2 ... itemN; do command1; command2… done;

示例如下:

for value in 1 2 3 4 5
do
    echo "The value is: $value"
done
# 输出
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5

while循环

while循环的语句格式如下:

while condition
do
    command
done

condition语句判断为true时,执行command语句;执行结束之后,继续判断condition语句,直到为false,结束执行。

示例如下:

value=1
while(( $value<=5 ))
do
    echo 值为:$value
    let "value++"
done
# 输出
值为:1
值为:2
值为:3
值为:4
值为:5

跳出循环

在循环的过程中,经常需要做出跳出循环的操作。这里又包含了两种情况,一种是跳出当前循环,进入下一次循环;另一种是,直接跳出循环语句,执行循环语句后面的代码。

第一种,跳出当前循环,进入下一次循环,使用continue命令。

第二种,跳出循环,使用break命令。

Shell函数

定义函数

可以在Shell脚本内定义函数。格式如下所示:

[ function ] functioName [()]

{

    action;

    [return int;]

}
  1. function关键字是可选的,可以设置,也可以不设置。

若对这个格式不是很理解,我们接下来就详细来说明。

我们先来尝试简单地使用函数。我们先定义一个函数,然后再调用它。如下所示:

# 定义一个函数,名为getName,其作用为打印字符串Shell
function getName(){
  echo "Shell"
}

# 调用函数getName
getName
# 输出
Shell

调用函数

直接使用函数名称即可调用函数。

在函数名称后面,再带上一些参数,便是调用函数并给函数传递了一些参数。

# 定义一个函数getName
function getName(){
  echo "Shell"
}

# 直接使用函数名调用函数
getName

# 定义一个函数hello
function hello(){
  echo "Hello $1"
}

# 直接使用函数名调用函数,并传递了一个字符串作为参数
hello "孙悟空"
# 输出
Shell
Hello 孙悟空

函数参数

函数是支持传递参数的,在函数体内部,通过$n的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数,以此类推。注意,$10不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。

# 定义一个函数hello
function hello(){
  echo "Hello $1"
}

# 直接使用函数名调用函数,并传递了一个字符串作为参数
hello "孙悟空"
# 输出
Hello 孙悟空

另外,还有几个特殊字符用来处理参数:

参数处理说明
$#传递到脚本的参数个数
$*以一个单字符串显示所有向脚本传递的参数
$$脚本运行的当前进程ID号
$!后台运行的最后一个进程的ID号
$@与$*相同,但是使用时加引号,并在引号中返回每个参数。
$-显示Shell使用的当前选项,与set命令功能相同。
$?显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

函数返回值

函数的返回值,可以显式使用关键字return返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值,可选值为0-255

return表示退出函数并返回一个退出值,脚本中可以在调用函数后,用$?获取到该退出值。

# 定义了一个函数sum,read命令用于在执行中输入数字,并设置到参数firstNum和secondNum
function sum(){
    echo "这个函数会对输入的两个数字进行相加运算..."
    echo "输入第一个数字: "
    read firstNum
    echo "输入第二个数字: "
    read secondNum
    echo "两个数字分别为 $firstNum$secondNum"
    return $(($firstNum+$secondNum))
}

# 运行函数sum,并通过$?获取到函数的返回值进行打印
sum
echo "输入的两个数字之和为$?"
# 输出
这个函数会对输入的两个数字进行相加运算...
输入第一个数字:
1
输入第二个数字:
2
两个数字分别为 12
输入的两个数字之和为3

函数返回值在调用该函数后通过$?来获得。

递归调用函数

什么叫做递归调用,便是函数自己调用自己。

函数库

一些注意事项

  1. 所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。
  2. Shell函数中定义的变量默认也是全局变量,它和在函数外部定义变量拥有一样的效果。

常见的命令

echo

echo命令用于字符串的输出。命令格式:

echo string

printf

printf也是一个输出命令,但是可以格式化字符串。命令格式:

printf  format-string  [arguments...]

test命令

Shell中的test命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。

数值测试

参数说明
-eq等于则为真
-ne不等于则为真
-gt大于则为真
-ge大于等于则为真
-lt小于则为真
-le小于等于则为真
# 使用test命令判断脚本输入第一个参数和第二个参数的大小比较
if test $1 -eq $2
then
        echo "数值相等"
elif test $1 -gt $2
then
        echo "$1大于$2"
else
        echo "${1}小于${2}"
fi
# 输出
$ sh test.sh 10 10
数值相等

$ sh test.sh 10 11
10小于11

$ sh test.sh 12 11
12大于11

字符串测试

参数说明
=等于则为真
!=不相等则为真
-z 字符串字符串的长度为零则为真
-n 字符串字符串的长度不为零则为真
# 使用test命令判断脚本输入第一个参数和第二个参数的字符是否相等
if test $1 = $2
then
        echo "相等"
fi

if test $1 != $2
then
        echo "不相等"
fi
$ sh test.sh aaa aaa
相等

$ sh test.sh aaa zzz
不相等

文件测试

参数说明
-e 文件名如果文件存在则为真
-r 文件名如果文件存在且可读则为真
-w 文件名如果文件存在且可写则为真
-x 文件名如果文件存在且可执行则为真
-s 文件名如果文件存在且至少有一个字符则为真
-d 文件名如果文件存在且为目录则为真
-f 文件名如果文件存在且为普通文件则为真
-c 文件名如果文件存在且为字符型特殊文件则为真
-b 文件名如果文件存在且为块特殊文件则为真
# 使用test命令判断脚本输入第一个参数指定的文件是否存在
if test -e $1
then
        echo "文件存在"
else
        echo "文件不存在"
fi
# 输出
$ sh test.sh "test.sh"
文件存在

$ sh test.sh "test.sh1"
文件不存在

其他

Shell中$各种含义

符 号含 义
$0脚本名
$#参数个数
$n传递给脚本的参数值,$1表示第1参数、$2表示第2参数
$?上次退出的状态(返回值),0没有错误,1错误
$*所有参数列表。"$*“时,是”$1 $2 … $n"的形式
$@所有参数列表。“$@“时,是”$1” “ 2 " … " 2" … " 2""n” 的形式
$$当前进程的编号(ProcessID)
$!shell最后运行的后台Process的PID
$var变量,会与后面的连接,如$var_a,会当做变量var_a
${var}变量,界定范围
$()(反引号)类似,里面执行完再返回值,所有shell通用
$[]可进行算术运算和逻辑运算,不支持浮点和字符串
$(())可进行算术运算和逻辑运算,不支持浮点和字符串。里面的变量可以省略$

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/902785.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

速通蓝桥杯嵌入式省一教程:(六)PWM输出

定时器除了用于最基本的定时器计时中断以外&#xff0c;还可以用于输出PWM(Pulse Width Modulation)波&#xff0c;即脉冲宽度调制波形&#xff0c;也就是频率与占空比均可改变的矩形波。下面我们就使用PA1端口生成PWM波。 在Cube中&#xff0c;首先需要将PA1设置成定时器的通…

Android LiveData原理之-setValue和数据倒灌原理分析

一图胜万言&#xff0c;直接上图吧&#xff01;有需要的同学们可以对着这张泳道图阅读源码&#xff0c;相信能够快速加深理解。

3:Ubuntu上配置QT交叉编译环境并编译QT程序到Jetson Orin Nano(ARM)

1.Ubuntu Qt 配置交叉编译环境 1.1 ubuntu 20.04安装Qt sudo apt-get install qtcreator 1.2 配置QT GCC配置同上 最后配置Kits 上面设置完成之后 &#xff0c;设置Kits 中的Device(这是为了能够直接把项目部署到arm设备上) 点击NEXT之后会出现连接被拒绝&#xff0c;不用担…

IEC61499/ OPCUA pub/sub 测试

OpenDACS 是基于OPCUA 信息模型的IEC61499 分布式自动控制系统。本文介绍它如何采用Opcua Pub/Sub 实现分布式设备中功能块之间的通信。 4diac 构建IEC61499 系统和应用 系统结构 试验系统共有三台设备&#xff0c;为了实验方便&#xff0c;我们让它们在一台Linux PC 上运行…

智能文件改名,一键与上上级目录名称同步,让文件整理更加便捷

在整理文件时&#xff0c;经常会遇到需要将文件名称与上上级目录名称保持一致的情况。手动逐个修改文件名不仅费时费力&#xff0c;还容易出错。现在&#xff0c;我们为你带来了一款智能文件改名工具&#xff0c;让你能够一键将文件名称改成跟上上级目录名称一样&#xff0c;让…

Qt+C++跑马灯-指示灯-风扇-虚线灯带-动画仿真

程序示例精选 QtC跑马灯-指示灯-风扇-虚线灯带-动画仿真 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<QtC跑马灯-指示灯-风扇-虚线灯带-动画仿真>>编写代码&#xff0c;代码整…

Vulnhub靶机系列 Infosec_Warrior1

InfoSecWarrior CTF 2020: 01官网地址 难易程度&#xff1a;So Easy 信息收集 主机发现 arp-scan -l端口扫描 nmap -A -p- 192.168.80.145目录爆破 dirsearch -u 192.168.80.145 -i 200访问80端口&#xff0c;只能看出是Apache站点&#xff0c;没有别的 访问一下sitemap.xm…

火山引擎ByteHouse:一套方案,让OLAP引擎在精准投放场景更高效

由于流量红利逐渐消退&#xff0c;越来越多的广告企业和从业者开始探索精细化营销的新路径&#xff0c;取代以往的全流量、粗放式的广告轰炸。精细化营销意味着要在数以亿计的人群中优选出那些最具潜力的目标受众&#xff0c;这无疑对提供基础引擎支持的数据仓库能力&#xff0…

开源ChatGPT系统源码 采用NUXT3+Laravel9后端开发 前后端分离版本

开源ChatGPT系统源码 采用NUXT3Laravel9后端开发 前后端分离版本 ChatGPT是一种基于AI的聊天机器人技术&#xff0c;它可以帮助用户与聊天机器人进行自然语言交流&#xff0c;以解决用户的问题或满足用户的需求。ChatGPT的核心技术是使用自然语言处理&#xff08;NLP&#xff…

设计模式之组合模式(Composite)的C++实现

1、组合模式的提出 在软件开发过程中&#xff0c;使用者Client过多依赖所操作对象内部的实现结构&#xff0c;如果对象内部的实现结构频繁发生变化&#xff0c;则使用者的代码结构将要频繁地修改&#xff0c;不利于代码地维护和扩展性&#xff1b;组合模式可以解决此类问题。组…

JQuery快速入门教程

1、JQuery快速入门 1.1、JQuery介绍 jQuery 是一个 JavaScript 库。所谓的库&#xff0c;就是一个 JS 文件&#xff0c;里面封装了很多预定义的函数&#xff0c;比如获取元素&#xff0c;执行隐藏、移动等&#xff0c;目的就 是在使用时直接调用&#xff0c;不需要再重复定义…

蓝牙 - BLE SPP的设计策略(Serial over BLE strategy)

在开发 BLE 连接产品的过程中&#xff0c;你可能会有这样的疑问&#xff1a;"Serial profile在哪里&#xff1f;也许你以为你在蓝牙技术联盟网站上滚动浏览长长的profile列表时错过了它。又或者&#xff0c;你根本就没去看&#xff0c;而是准备选择更快的方法&#xff0c;…

第 359 场 LeetCode 周赛题解

A 判别首字母缩略词 签到题… class Solution { public:bool isAcronym(vector<string> &words, string s) {string pf;for (auto &s: words)pf.push_back(s[0]);return pf s;} };B k-avoiding 数组的最小总和 贪心&#xff1a;从 1 1 1开始升序枚举&#xff0c…

mybatis-plus--配置-(sql)日志输出-自动填充-分页-多数据源-逻辑删除

写在前面&#xff1a; 本文主要介绍mybatis-plus的配置&#xff0c;以后在有的时候在补充。欢迎交流。 文章目录 日志输出自动填充分页全局字段配置多数据源 日志输出 调试的时候需要看执行的sql&#xff0c;这时候就很需要日志来记录查看了。 mybatis-plus的日志配置在yml…

葡萄目标检测(yolov8模型,无需修改路径,python代码,解压缩后直接运行)

运行效果视频&#xff1a;葡萄目标检测&#xff08;yolov8模型&#xff0c;无需修改路径&#xff0c;python代码&#xff0c;解压缩后直接运行&#xff09;_哔哩哔哩_bilibili 1.采用yolov8模型 models文件夹保存的是yolov8的训练好的模型参数 PinotNoir文件夹存放的是训练集 …

局部变量可能会引发的错误---误判---用阶乘函数求强数的 Python 程序中遇到的问题

背景介绍 今天遇到这样一个额需求&#xff1a;用阶乘函数求强数的 Python 程序。所谓强数&#xff0c;就是一个特殊数字&#xff0c;满足其所有数字阶乘的和应等于数字本身的条件。 问题描述 def facorial_of_number(number):result 1for i in range(1, number 1):result *…

如何使用Python实现遥感彩色合成?

综述 遥感影像真彩色合成是一种将多光谱遥感影像转换为真实感彩色影像的技术。它通过将不同波段的遥感数据进行组合&#xff0c;以模拟人眼对地物颜色的感知&#xff0c;从而提供更直观、更易于理解的影像信息。 库索引名&#xff1a;arcpy.CompositeBands_management 通过不同…

如何在window下cmd窗口执行linux指令?

1.Git&#xff1a;https://git-scm.com/downloads(官网地址) 2.根据自己的实际路径,添加两个环境变量 3.重启电脑

[oneAPI] 使用Bert进行中文文本分类

[oneAPI] 使用Bert进行中文文本分类 Intel Optimization for PyTorch基于BERT的文本分类模型数据预处理数据集定义tokenize建立词表转换为Token序列padding处理与mask 模型 结果OneAPI参考资料 比赛&#xff1a;https://marketing.csdn.net/p/f3e44fbfe46c465f4d9d6c23e38e0517…