python编写脚本教程_使用 Python 编写脚本并发布

使用 Python 编写脚本并发布

P1: 脚本

通常在 Linux 服务器上会遇到在命令行中输入命令的操作,而有些操作包含的命令数目较多或者其中的命令包含的参数较多,如果一个一个的敲命令的话就太麻烦了,有几种做法可以简化操作:

使用 alias 为命令编写别名,比如我之前开发一个网站程序 minor-sspymgr 时,经常需要上传修改后的代码,更新服务器上的代码,重启网站程序。为了方便,我定义一个 alias 别名命令:

alias updateMgr='cd ~/minor-sspymgr/ && git pull origin master && pm2 restart sspymgr'

这种方法的优点是很方便简单,把常用的命令组合到一起,用一个别名表示即可使用。当然,它的缺点也很明显,就是不能执行一些复杂的命令,而且难以将参数应用到命令中。

编写一个 .sh 脚本,我之前写简单脚本时用的都是 bash,对于上述例子,用 sh 脚本编写起来也很类似,可以简单的把上述命令以 && 拆分为 3 行:

#!/bin/bash

cd ~/minor-sspymgr/

git pull origin master

pm2 restart sspymgr

当然了,实际的脚本远非如此简单,可以用 $1 ... $n 获取命令行参数,执行一些更复杂的逻辑。

为什么用 Python 写脚本

既然用 bash 已经可以编写一些脚本了,那么为什么我还要用 Python 编写脚本呢?原因有两个:1. bash 用的不多,学的也早,而且 bash 和常用的编程语言的语法有些差别,很多内容都容易忘记,用 Python 写的话也可以熟悉 Python(尽管我是从 flask 制作一个 WSGIServer 开始使用 Python 的),2. Python 的库很多也很方便使用,编写脚本给人一种流畅的感觉。当然最主要的原因就是因为 Python 里面有 argparse 这个库,对于解析命令行参数来说十分方便。

如何解析命令行参数

bash 脚本里面获取命令行参数的方式很简单,但是解析起来却比较麻烦,如果有 bash 解析命令行参数的库,希望可以推荐给我。不过即使有这样的库,估计我还是会选择 Python 来编写脚本了。在 Python 里解析命令行参数的模块比较多,有 getopt、optparse、argparse 等 1。目前我只用过 argparse,因此这里也只会涉及到如何用 argparse 来解析命令行参数。至于前两个模块,如果有兴趣的话,可以自行了解。argparse 使用起来非常简单:

from argparse import ArgumentParser

parser = ArgumentParser(description="""Run this script under SUPER USER privilege. Create or remove git repository

under direcotry: {}. Currently only works for Linux. Most operations are only tested under Linux.

Script version : {}.

""".format(config["repo_dir"], __version__))

parser.add_argument("-V", "--version", help="Print this script version", action="store_true")

args = parser.parse_args()

if args.version:

print("Script version is {}".format(__version__))

上面这几行代码就做好了一个简单的命令行解析功能,当我们输入 script.py -V 的时候就会打印出脚本的版本。不需要在意命令行参数的位置或者是否必须要加上这个参数,只需要将注意力放在代码的逻辑上即可,argparse 这个模块可以极大的方便我们解析命令行参数。

P2: 示例:初始化 git 仓库的脚本

之前用 git 搭建过源代码管理服务器 2、3。如果要在这样的服务器上添加一个共享仓库,就需要在仓库根目录下面执行一些操作了。比如说,我的 git 仓库存放的目录是 /src 这个目录下面的所有文件及文件夹的属主和属组都是 git,要想新建一个共享仓库,最开始我的做法是:

cd /src

mkdir newrepo && cd newrepo

git init --bare --shared

cd ..

sudo chown -R git:git newrepo && sudo chmod -R g+rwx newrepo

步骤还是有点多的,每次都要敲这么多命令很麻烦,把这些命令写到 bash 脚本中,比如叫做 gitrepo.sh,给它加上 x 执行权限,在终端里输入 sudo gitrepo.sh reponame 就能完成上面的操作。

用 Bash 编写的脚本

Bash 脚本,编写简单,就是把在命令行中敲过的命令依次写到文件中即可,但是对于不常写 bash 脚本的我来说,要编写一个完备的脚本,并且要包含参数、异常处理等逻辑来说比较麻烦:

#!/bin/bash

# filename: gitrepo.sh

# @author BriFuture

# @details create bare and shared repository within /src directory

repoName=$1

if [ -z "$repoName" ]; then

echo "Repo is empty!"

exit 1

fi

dotpos=`expr index "$repoName" "."`

if [ "$dotpos" -gt 0 ]; then

echo "found";

else

repoName=$repoName".git"

fi

# go to the repository dir

cd /src

mkdir $repoName

cd $repoName

echo "Init git repo in $repoName"

git init --bare --shared

# change the own of repository

cd ../

sudo chown -R git:git $repoName

sudo chmod -R g+rwx $repoName

用 Python 编写的脚本

实际上,我用 Python 重新编写这个脚本时,在参数中加入了更多的可选项,此前的 bash 脚本只能够添加仓库,这个全新的脚本加入了其他操作:添加新的仓库,列出所有仓库,删除一个仓库。并且完善了命令行的帮助信息,为脚本添加了配置文件以及输出日志。

另外在执行脚本的过程中需要用到超级用户的权限,因此在脚本中添加了检查当前用户权限的功能:

def is_root():

if hasattr(os, "getuid"):

return os.getuid() == 0

return False

该 Python 脚本的主要功能是添加和删除仓库(目录),添加仓库的操作如下,分别是创建目录,执行 git init --bare --shared 命令,更改文件属主和属组的操作(实际的脚本中包含一些日志记录和异常处理的代码):

from pathlib import Path

def createRepo(repo: Path):

if repo.exists():

return

repo.mkdir(parents=True)

subprocess.run(["git", "init", "--bare", "--shared", str(repo.absolute())])

shutil.chown(repo, config["user"], config["group"])

删除仓库的操作更加简单,调用 shutil 递归删除文件夹即可,不能使用 repo.rmdir() 函数,因为一般仓库文件夹是非空的:

import shutil

def deleteRepo(repo: Path):

if not repo.exists():

return

shutil.rmtree(str(repo))

罗列所有仓库使用 Path.iterdir() 函数即可。

这样一个可以使用的脚本就制作完成了,如果只是单纯的编写一个脚本的话,可以在文件的开头加上 #!/usr/bin/python3 这样的标记,表明这是一个可执行的 Python3 脚本,在 linux 系统上给它加上 x 权限,比如这个文件的名称为 gitrepo.py,我们可以在终端中输入 gitrepo.py -h 或者 python3 gitrepo.py -h 查看这个命令的帮助信息。

P3: 以 wheel 包的形式发布

前面说过,我们可以把写好的 Python 文件当做脚本执行,但是每次都要敲 gitrepo.py -h 这样的命令,能不能就像平时用 ls 这些命令一样直接敲 gitrepo -h 呢?最简单的是用 ln 建立软链接:sudo ln -s /path/to/gitrepo.py /usr/bin/gitrepo,但是这里我们可以借助 pypi 发布我们已经写好的命令,将我们的脚本发布到 pypi 上,那么还可以在没有该脚本的机器上利用 pip 进行安装。

以 brifuture-facilities 这个项目为例,在项目的根目录下面新建一个 setup.py 文件,输入以下内容:

# -*- coding: utf-8 -*-

from setuptools import setup, find_packages

with open("README.md", "r", encoding="utf-8") as fh:

long_description = fh.read()

with open('requirements.txt', "r", encoding="utf-8") as f:

requires = f.read().splitlines()

from myfacilities import __version__

setup(

name = "brifuture-facilities",

packages = find_packages(where='.'),

version = __version__,

entry_points = {

"console_scripts": [

'bf_broadcast = myfacilities.broadcast:main',

'bf_gitrepo = myfacilities.gitrepo:main',

]

},

description = "BriFuture's scripts set, all scripts will be written with Python3",

author = "BriFuture",

author_email = "jw.brifuture@gmail.com",

license = "GPLv3",

url = "http://github.com/brifuture/",

install_requires = requires,

include_package_data = True,

zip_safe=True,

exclude_package_data = {'': ['__pycache__']},

# download_url = "",

keywords = [ "webserver", "socks-manager" ],

classifiers = [

"Programming Language :: Python",

"Programming Language :: Python :: 3" ,

"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",

"Operating System :: OS Independent"

],

long_description = long_description,

long_description_content_type="text/markdown",

)

我们需要利用的是 setuptools,从这个模块中导入 setup,它的参数都很直观,我们想要添加一个可执行的脚本时,在 entry_points 关键字参数中添加即可,如:

entry_points = {

"console_scripts": [

'bf_broadcast = myfacilities.broadcast:main',

'bf_gitrepo = myfacilities.gitrepo:main',

]

},

由于这个项目中的文件是包的一部分,所以我没法直接使用 python 运行其中的某个脚本,像 python3 myfacilities.gitrepo -h 是无法运行的,但是借助于 setuptools,我们可以将写好的程序安装到机器中,python3 setup.py install 可以通过 setup.py 文件进行安装,也可以使用 pip install . 进行安装,详细的教程可以在 文档 中找到。

接下来制作 wheel 包,命令很简单:

python3 setup.py sdist bdist_wheel

这样会将我们的代码打包到 dist/ 目录下。

我们需要将制作好的程序发布到 pypi 上,安装好 twine: pip install twine, 在 $HOME 目录(linux) 或者 C:\Users\yourname\ 目录(windows)下新建一个 .pypirc 文件,输入下面的内容:

[distutils]

index-servers=

pypi

testpypi

[pypi]

repository: https://upload.pypi.org/legacy/

username: yourname

password: yourpasswd

[testpypi]

repository: https://test.pypi.org/legacy/

username: yourname

password: yourpasswd

接下来就可以发布了,但是不要着急,正式发布前都请将制作好的包发布到 testpypi 上:

python3 -m twine upload -r testpypi dist/* --skip-existing

等你确认一切无误后,在将 -r testpypi 参数换成 -r pypi 以便正式发布。

P4: 小结

尽管制作一个小巧、实用而且完备的 Python 脚本很有意思,但是要想做出一个实用、对用户友好的脚本,还是需要花一些时间的。实际上如果要为用户提供更加友好的实用方式,可以考虑以界面的形式为用户提供操作,比如说以网页的形式提供操作,在服务器后台对用户操作进行处理。不过你也可能注意到了,这个脚本的功能其实就是很基础的增删查改。

上面示例的 Python 脚本在使用过程中会用到超级用户权限,为了防止操作失败,在添加、删除仓库时必须提供超级用户权限,否则脚本将会退出,还有一种方式可以在运行时获得超级用户权限,就是使用 [elevate][https://github.com/barneygale/elevate] 进行提权,具体的使用方式还没来得及看,不过我猜测应该需要向 elevate 提供一个超级用户密码的文件。

如果你想仔细查看上述 Python 示例代码的话,可以在 Github 上找到 brifuture-facilities 项目的代码。如果你觉得我的文章或者其中的代码对你有帮助,请给它点个赞。

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值