admin 管理员组

文章数量: 887021

七问ChatGPT, 剑指shell脚本编写

    • step1: 初问
    • step2: 再问
    • step3: 三问
    • step4: 四问
    • step5: 五问
    • step6: 问个der
    • step7: 解决问题
    • step8: 小问一下
    • 关于ChatGPT
    • 思考

昨天浏览一篇关于脚本的技术文章的时候, 偶然看见一篇文章中写道关于mysql备份的脚本.
但是这个脚本时基于本地的MySQL服务写的, 由于我近年来使用的mysql基本上都是docker部署的,
因此, 我就在想, 如何能把脚本改造成docker部署的服务也能使用的脚本呢?
而我, 作为shell脚本学习的劣等生, 就想到了最近很火的一个技术 ——ChatGPT
嗯, 就觉定是你了

阅读提示

  • 如果有些大佬shell脚本玩的非常6的话, 可以跳过此文.
  • 本文使用的是ChatGPT3模型搭建的镜像网站, 现在ChatGPT已经迭代到ChatGPT4了,
    可能已经完全解决了我在这一版所以才所存在的问题. 但目前没有机会使用最新版本的工具,
    因此本文仅表达个人对ChatGPT3这个版本的使用看法.

step1: 初问

一开始我没想那么多, 就把当时的想法表达出来. 所以问题表述没那么详细, 建议描述问题时尽量详细点.
理论上来说, 描述的越详细, 提供的代码就越规范, 正确率高


可以看到, 真的很神奇, ChatGPT能够基本理解我所提出的问题, 并给我提供了如上图的脚本代码, 而且贴心的为我加上了中文注释. 不仅如此, 在脚本代码提供之后还为我们总结了脚本的过编写核心逻辑

在此特将脚本分享在下面, 方便各位读者尝试

#!/bin/bash
# 定义变量
MYSQL_CONTAINER_NAME="mysql" # MySQL容器的名称
MYSQL_DB_NAME="mydatabase" # MySQL数据库的名称
BACKUP_DIR="/backup/mysql" # 备份文件存放的目录
# 创建备份目录
mkdir -p $BACKUP_DIR
# 获取当前时间
DATETIME=$(date +%!Y(MISSING)%!m(MISSING)%!d(MISSING)%!H(MISSING)%!M(MISSING)%!S(MISSING))
# 备份MySQL数据库
docker exec $MYSQL_CONTAINER_NAME sh -c 'exec mysqldump --databases $MYSQL_DB_NAME -uroot -p"$MYSQL_ROOT_PASSWORD"' > $BACKUP_DIR/$MYSQL_DB_NAME-$DATETIME.sql
# 压缩备份文件
gzip -f $BACKUP_DIR/$MYSQL_DB_NAME-$DATETIME.sql
# 删除7天前的备份文件
find $BACKUP_DIR -type f -name "*.gz" -mtime +7 -delete

唯一美中不足的是有两点

  • 其在说明创建完脚本后, 是不能够直接运行的, 还缺少一步为脚本授权的操作 chmod +x 脚本名称
  • 在备份MySQL数据库这一步, 执行的脚本中变量 MYSQL_ROOT_PASSWORD没定义, 需要自己在脚本开头定义下

修改上面两点之后执行脚本, 结果仍然执行失败, 错误信息如图所示

step2: 再问

我们将执行脚本时出现的错误信息反馈给ChatGPT, 看它如何进行回答


可以看出, ChatGPT确实是根据我的反馈, 对代码进行了适当的修改, 并在结尾说明修改的内容.
我对第10行的单引号改成了双引号,并使用了反斜线来转义双引号,这样就可以在命令替换中使用变量了
为了能够清晰的观察出改动了什么, 这里通过代码比对的工具对两个代码进行比对来查看二者不同



并且在比对的时候, 我突意识到如果按照上面的方式进行全量备份的话, 会十分耗时,
因此, 我决定修改问题条件, 并让ChatGPT重新帮助我编写脚本

step3: 三问

将问题再次进行凝练之后, ChatGPT提供的脚本如下

相关代码(这部分代码很重要, 后面还会用到)

#!/bin/bash
# 定义变量
MYSQL_CONTAINER_NAME="mysql" # MySQL容器的名称
BACKUP_DIR="/backup/mysql" # 备份文件存放的目录
# 创建备份目录
mkdir -p $BACKUP_DIR
# 获取当前时间
DATETIME=$(date +%!!(MISSING)Y(MISSING)%!!(MISSING)m(MISSING)%!!(MISSING)d(MISSING)%!!(MISSING)H(MISSING)%!!(MISSING)M(MISSING)%!!(MISSING)S(MISSING))
# 获取MySQL中所有的数据库名称
DATABASES=$(docker exec $MYSQL_CONTAINER_NAME sh -c "exec mysql -uroot -p\$MYSQL_ROOT_PASSWORD -s -e 'show databases;'")
# 备份每个数据库
for DB_NAME in $DATABASES
do
  if [ $DB_NAME != "information_schema" ] && [ $DB_NAME != "performance_schema" ] && [ $DB_NAME != "mysql" ]; then
    docker exec $MYSQL_CONTAINER_NAME sh -c "exec mysqldump $DB_NAME -uroot -p\$MYSQL_ROOT_PASSWORD" > $BACKUP_DIR/$DB_NAME-$DATETIME.sql
    gzip -f $BACKUP_DIR/$DB_NAME-$DATETIME.sql
    find $BACKUP_DIR -type f -name "$DB_NAME*.gz" -mtime +7 -delete
  fi
done

这里在代码底部给出了修改的内容


我们来修改下此脚本, 修改变量MYSQL_CONTAINER_NAME, BACKUP_DIRMYSQL_ROOT_PASSWORD, 然后执行脚本,
可以看到依旧报错, 最明显的错误是 Using a password on the command line interface can be insecure

step4: 四问

我们继续将这个问题抛给ChatGPT, 看看它是怎么回答

相关代码

#!/bin/bash
# 定义变量
MYSQL_CONTAINER_NAME="mysql" # MySQL容器的名称
BACKUP_DIR="/backup/mysql" # 备份文件存放的目录
MYSQL_CONFIG_FILE="/root/.myf" # MySQL的配置文件,用于存储用户名和密码
# 创建MySQL的配置文件
echo "[client]" > $MYSQL_CONFIG_FILE
echo "user=root" >> $MYSQL_CONFIG_FILE
echo "password=\$MYSQL_ROOT_PASSWORD" >> $MYSQL_CONFIG_FILE
# 创建备份目录
mkdir -p $BACKUP_DIR
# 获取当前时间
DATETIME=$(date +%!!(MISSING)!(MISSING)Y(MISSING)%!!(MISSING)!(MISSING)m(MISSING)%!!(MISSING)!(MISSING)d(MISSING)%!!(MISSING)!(MISSING)H(MISSING)%!!(MISSING)!(MISSING)M(MISSING)%!!(MISSING)!(MISSING)S(MISSING))
# 获取MySQL中所有的数据库名称
DATABASES=$(docker exec $MYSQL_CONTAINER_NAME sh -c "exec mysql -s -e 'show databases;'")
# 备份每个数据库
for DB_NAME in $DATABASES
do
  if [ $DB_NAME != "information_schema" ] && [ $DB_NAME != "performance_schema" ] && [ $DB_NAME != "mysql" ]; then
    docker exec $MYSQL_CONTAINER_NAME sh -c "exec mysqldump $DB_NAME" > $BACKUP_DIR/$DB_NAME-$DATETIME.sql
    gzip -f $BACKUP_DIR/$DB_NAME-$DATETIME.sql
    find $BACKUP_DIR -type f -name "$DB_NAME*.gz" -mtime +7 -delete
  fi
done
# 删除MySQL的配置文件
rm $MYSQL_CONFIG_FILE

在新的脚本中,核心就是在原来脚本的基础上创建了一个MySQL账号密码信息的配置文件/root/.myf,
通过将重要信息保存在配置文件来解决上面问题

那么, 我们修改脚本文件中 user, password 信息后, 继续执行如下代码, 可以看到提示账户密码信息不对.

step5: 五问

本着尽量多依靠ChatGPT的想法, 继续将代码执行的问题反馈
在提问时, 我试图引诱他往这方面考虑, 我们且看他的回答

相关代码

#!/bin/bash
# 定义变量
MYSQL_CONTAINER_NAME="mysql" # MySQL容器的名称
BACKUP_DIR="/backup/mysql" # 备份文件存放的目录
# 创建备份目录
mkdir -p $BACKUP_DIR
# 获取当前时间
DATETIME=$(date +%!!(MISSING)Y(MISSING)%!!(MISSING)m(MISSING)%!!(MISSING)d(MISSING)%!!(MISSING)H(MISSING)%!!(MISSING)M(MISSING)%!!(MISSING)S(MISSING))
# 获取MySQL中所有的数据库名称
DATABASES=$(docker exec $MYSQL_CONTAINER_NAME sh -c "exec mysql -uroot -p\$MYSQL_ROOT_PASSWORD -s -e 'show databases;'")
# 备份每个数据库
for DB_NAME in $DATABASES
do
  if [ $DB_NAME != "information_schema" ] && [ $DB_NAME != "performance_schema" ] && [ $DB_NAME != "mysql" ]; then
    docker exec $MYSQL_CONTAINER_NAME sh -c "exec mysqldump $DB_NAME -uroot -p\$MYSQL_ROOT_PASSWORD" > $BACKUP_DIR/$DB_NAME-$DATETIME.sql
    gzip -f $BACKUP_DIR/$DB_NAME-$DATETIME.sql
    find $BACKUP_DIR -type f -name "$DB_NAME*.gz" -mtime +7 -delete
  fi
done

可以看到, ChatGPT仅仅在三问给出的代码基础上把代码定义成变量, 然后在执行备份命令时加上这些参数,
这种执行方式结果我们可想而知, 依旧是失败

这里我已经发现, 对于ChatGPT来说, 现在是陷入了一个循环: 无论是账号密码定义在脚本最开始定义, 还是在脚本执行时添加, 执行备份的时候都会出现Using a password on the command line interface can be insecure, 而将问题再次反馈给ChatGPT之后, 就会给出一种将账号密码信息保存成配置文件之后然后执行的脚本解决方案, 但是在执行其给出的脚本执行仍会出现账号密码不正确的情况, 再然后将问题进行反馈, 得到的脚本几乎与最开始的脚本一样.

step6: 问个der

就这样, 在我继续追问时, ChatGPT竟然"发脾气了", 不允许继续追问了, 没想到你竟然这么高冷 [○・`Д´・ ○]
所以, 我还是打算自己修改下这部分的代码

step7: 解决问题

通过step5的分析, 结合自己的判断可知, 当前脚本最好应从step4的提供的代码开始进行调试. 那么话不多说, 我们开始调试吧.


根据上面脚本执行的报错, 可以看到最明显的错误就是提示账号密码不正确,
而我自己也核对了账号密码也没问题, 于是开始从脚本上面找问题

ChatGPT也描述这段代码的逻辑, 我们再次嚼一下

在这个脚本中,我们创建了一个MySQL的配置文件/root/.myf,并在其中存储了用户名和密码。我们使用echo命令将用户名和密码写入配置文件。然后在使用mysqldump命令备份MySQL数据库时,不再需要在命令行中输入密码,而是使用配置文件中的密码。备份完成后,我们删除了MySQL的配置文件。希望这个修改后的脚本可以帮助你解决这个问题。

而我发现, 在执行备份命令的时候, 是需要进入MySQL的命令行的, 但是我的MySQL是通过docker部署的.
因此需要进入MySQL的docker容器内的命令行才能执行备份命令.
所以, 存储MySQL信息的配置文件只有在docker容器内才可以被发现并执行.
为了验证自己的猜想, 我决定进入MySQL的docker容器中去查看是否有这个配置文件 (其实不用查看,
因为脚本中就不存在复制MySQL信息的配置文件到Docker容器的命令! 但是抱着眼见为实的想法还是进行了验证)

这时, 就需要docker cp命令了, 利用docker cp 来将生成的MySQL信息的配置文件复制到容器中, 修改后代码如下docker cp /目录/文件名 容器id:目录 , 这里需要利用docker ps命令来获取当前容器的容器id

#!/bin/bash
# 定义变量
MYSQL_CONTAINER_NAME="mysql" # MySQL容器的名称
BACKUP_DIR="/backup/mysql" # 备份文件存放的目录
MYSQL_CONFIG_FILE="/root/.myf" # MySQL的配置文件,用于存储用户名和密码
# 创建MySQL的配置文件
echo "[client]" > $MYSQL_CONFIG_FILE
echo "user=账号" >> $MYSQL_CONFIG_FILE
echo "password=密码" >> $MYSQL_CONFIG_FILE
# 将生成的文件复制到容器中 ( 这里需要注意容器id应改为自己的 )
docker cp /root/.myf  cf22ab9c8f17:/root
# 创建备份目录
mkdir -p $BACKUP_DIR
# 获取当前时间
DATETIME=$(date +%!!(MISSING)!(MISSING)Y(MISSING)%!!(MISSING)!(MISSING)m(MISSING)%!!(MISSING)!(MISSING)d(MISSING)%!!(MISSING)!(MISSING)H(MISSING)%!!(MISSING)!(MISSING)M(MISSING)%!!(MISSING)!(MISSING)S(MISSING))
# 获取MySQL中所有的数据库名称
DATABASES=$(docker exec $MYSQL_CONTAINER_NAME sh -c "exec mysql -s -e 'show databases;'")
# 备份每个数据库
for DB_NAME in $DATABASES
do
  if [ $DB_NAME != "information_schema" ] && [ $DB_NAME != "performance_schema" ] && [ $DB_NAME != "mysql" ]; then
    docker exec $MYSQL_CONTAINER_NAME sh -c "exec mysqldump $DB_NAME" > $BACKUP_DIR/$DB_NAME-$DATETIME.sql
    gzip -f $BACKUP_DIR/$DB_NAME-$DATETIME.sql
    find $BACKUP_DIR -type f -name "$DB_NAME*.gz" -mtime +7 -delete
  fi
done
# 删除MySQL的配置文件
rm $MYSQL_CONFIG_FILE

可以看到执行脚本之后, 仍然给出了警告信息

但是, docker 容器里面已经存在MySQL账号密码信息的配置文件(算是成功了一半)

step8: 小问一下

本着简单的事情问ChatGPT, 复杂的问题自己来解决的思路
继续上面执行的问题交给ChatGPT(没错, 我又偷懒了~)


根据提示然后继续修改代码

执行后依然报错, 很容易推测出是转义符号和空格会导致生成备份文件失败,因此我们可以通过-将日期和时间进行连接

最终代码

#!/bin/bash
# 定义变量
MYSQL_CONTAINER_NAME="mysql" # MySQL容器的名称
BACKUP_DIR="/backup/mysql" # 备份文件存放的目录
MYSQL_CONFIG_FILE="/root/.myf" # MySQL的配置文件,用于存储用户名和密码
# 创建上面需要的MySQL的配置文件, 主要替换自己mysql对应的用户名和密码
echo "[client]" > $MYSQL_CONFIG_FILE
echo "user=mysql账号" >> $MYSQL_CONFIG_FILE
echo "password=mysql密码" >> $MYSQL_CONFIG_FILE
# 将生成的文件复制到容器中 ( 这里需要注意容器id应改为自己的 )
docker cp /root/.myf  cf22ab9c8f17:/root
# 创建备份目录
mkdir -p $BACKUP_DIR
# 获取当前时间
DATETIME=$(date +%Y-%m-%d-%H:%M:%S)
# 获取MySQL中所有的数据库名称
DATABASES=$(docker exec $MYSQL_CONTAINER_NAME sh -c "exec mysql -s -e 'show databases;'")
# 备份每个数据库
for DB_NAME in $DATABASES
do
  if [ $DB_NAME != "information_schema" ] && [ $DB_NAME != "performance_schema" ] && [ $DB_NAME != "mysql" ]; then
    docker exec $MYSQL_CONTAINER_NAME sh -c "exec mysqldump $DB_NAME" > $BACKUP_DIR/$DB_NAME-$DATETIME.sql
    gzip -f $BACKUP_DIR/$DB_NAME-$DATETIME.sql
    find $BACKUP_DIR -type f -name "$DB_NAME*.gz" -mtime +7 -delete
  fi
done
# 删除MySQL的配置文件
rm $MYSQL_CONFIG_FILE

执行脚本后的效果


关于ChatGPT

在博客写完后, 又在b站上面了解下ChatGPT, 特此分享下学习到的内容.

ChatGPT的概念

  • ChatGPT的实质功能是单字接龙
  • 长文由单字接龙的自回归所生成
  • 通过提前训练才能让它生成人们想要的问答, 训练方式是让它按照问答范例来做单字接龙.
    这样训练是为了让它学会能举一反三的规律, 缺点是可能混淆记忆,无法直接查看和更新所学. 且高度依赖学习材料.

ChatGPT 的基础原理(对应下面三个阶段)

  • 无监督学习
  • 监督学习
  • 强化学习

ChatGPT 的三个训练阶段

  • “开卷有益”阶段:
    让ChatGPT对海量互联网文本做单字接龙,以扩充模型的词汇量、语言知识、世界的信息与知识. 使ChatGPT从“哑巴鹦鹉”变成“脑容量超级大的懂王鹦鹉”
  • “模板规范”阶段:
    让ChatGPT对优质对话范例做单字接龙,以规范回答的对话模式和对话内容。使ChatGPT变成“懂规矩的博学鹦鹉”.
  • “创意引导”阶段:
    让ChatGPT根据人类对它生成答案的好坏评分来调节模型, 以引导它生成人类认可的创意回答. 使ChatGPT变成“既懂规矩又会试探的博学鹦鹉’

意义和价值

  • ChatGPT 的革命意义是向人们展示了大语言模型的可行性(为此前几天61岁李开复准备筹备创建新公司).
  • 人类群体通过语言处理来实现知识的创造、继承和应用
  • 机器处理语言有着速度快、记忆大、覆盖广、无疲劳的优点
  • 大语言模型能减轻语言处理工作, 改变人与人、人与机器的协作方式
  • 人类的理解和机器的理解不同,语言模型不知道符号的指代
  • 大语言模型对社会的未来影响,相当于口语、文字、电脑、互联网对社会的影响.
  • 对教育界、学术界、新闻界、内容生产行业的影响颇深. 它将方便人类对既有知识的继承.
    推进教育去培养高层次人才, 也将带来网络安全和社会安全的新挑战

思考

通过以上对话可以得出结论, ChatGPT虽然已经很智能了, 甚至能够强到会写代码了.
但是, 在很多情况下, 给出的代码往往只是对每个单独功能代码的堆砌(个人感觉).
并且, 因为它自身没有编译器, 无法验证自己提供的代码, 也就是说它无法保证代码的正确性, 健壮性以及并发性,.
因此, AI 当前并不能取代人类进行编码. 但ChatGPT在当下可以作为相关技术领域开发人员提升生产力水平的一个辅助工具. 由ChatGPT来写出代码, 技术人员来进行修改和调试. 最终较为快速的实现代码编写.
或许, 不久的将来, 随着AI技术的成熟, 能够最终实现写出的代码复制即可运行, 并且健壮性以及并发性都能得到保证的代码.
那时候, 可能一些程序员的工作就完全会被替代了…
为了不被淘汰, 我们也要学习拥抱新知识, 去学习如何使用它.
一些新工具的出现可能会淘汰调一批人, 但是却大概率淘汰不了会灵活使用这些新工具的人.


就这样, 在ChatGPT的帮助下, 我以一个外行的身份写完了一个脚本:
实现在docker容器中能够将mysql中所有数据库数据进行备份
虽然我已经把问题说的尽量简单, 但是一点点的调试确实比较繁琐且费时. 可能是我对ChatGPT不太熟悉的原因
其实后面还可以做成, 开机自启动+每天定时执行脚本功能, 后续有机会我会继续进行分享.
也欢迎大家在评论区相互交流~~~

本文标签: 我写 脚本 很感人 结局 ChatGpt