如何高效使用xonsh脚本编写、迁移与调优?
摘要:xonsh 是 python 驱动的 shell, 在操作效率, 交互和外部功能的先进性上比 bash 等优秀, 并且十分容易上手. 但相应地, 它是一个新兴的 shell, 并且不是所谓 "POSIX Shell
xonsh 是 python 驱动的 shell, 在操作效率, 交互和外部功能的先进性上比 bash 等优秀, 并且十分容易上手.
但相应地, 它是一个新兴的 shell, 并且不是所谓 "POSIX Shell"(尽管某些行为比较相似), 加上现有中文相关文章属实不深, 故自己做了一些较深的了解, 在此处记录心得, 若有错误请您指出, 不胜感谢.
xonsh 的提示符为 @, 因为它读作 "consh", 脚本文件扩展名为 .xsh, 官方定义的 markdown 代码块标签也是 xsh
截至本文最后更新, xonsh 的最高版本是 0.22.8
关于 xonsh 的安装和基本自定义, 本文不作赘述, 您可以阅读 Linux 中国等发布的新闻稿或者直接阅读 xonsh 官方安装教程, 安装并使用 xonfig web 等工具
特殊语法
Shell 与 Python 的集成是 xonsh 易用性的根源, xonsh 向下直接兼容多数 python 脚本语法, 并且有提供独特语法以便将 python 和 shell 集成
命令解释与机制相关
引用和处理字符串变量
在 xonsh 中, 你可以直接使用 print(x) 输出一个变量和对象, 但若想将它作为 touch 命令的参数呢? xonsh 能带你告别 bash 丑陋的字符串拼接和 for 语法.
xonsh 使用 @() 操作符在 shell 环境中引用一个变量, 它会自动对字符串对象进行 str() 而不是 repr() 操作(也即直接追加字符串), 可以通过下列代码验证: (注意, 对于其他类型 @() 还有其他优雅的行为, 详见下文)
tmp @ text = "Hello\nWorld"
tmp @ repr(text)
"'Hello\\nWorld'"
tmp @ str(text)
'Hello\nWorld'
tmp @ touch @(text)
tmp @ ls
'Hello'$'\n''World' # 文件名中真的有换行
tmp @ # 如果是 repr(), 就会创建 'Hello\nWorld' (无转义)
因此你可以这样创建一组数字序号文件
tmp @ for i in range(30):
touch @(i)
tmp @ ls
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29
tmp @
或者方便地补0
tmp @ for i in range(30):
touch @(str(i).zfill(2))
tmp @ ls
00 02 04 06 08 10 12 14 16 18 20 22 24 26 28
01 03 05 07 09 11 13 15 17 19 21 23 25 27 29
同样的简单操作若用 bash 进行, 需要:
for i in {0..29}; do touch $(printf "%02d" $i); done
或
# 避免命令替换的子 shell 开销
for i in {0..29}; do
printf -v name "%02d" "$i"
touch "$name"
done
python 还有 bash 无法提供的一系列支持库与工具, 可处理多种格式文件而无需引用外部程序; 并且处理含有奇葩字符的文件名, xonsh 可以使用字符串的 repr 集成到命令中很难炸掉
不过, 同样的操作若用纯 python 脚本/REPL进行, 需要:
from pathlib import Path
for i in range(0, 30):
name = str(i).zfill(2)
path = Path(name)
path.touch()
这两种对比足以显示 xonsh 的优越性
别名与 aliases
在 xonsh 中, 别名被存储在全局的 aliases -- 一个兼容字典 API 的 xonsh.aliases.Aliases 对象中.
像这样设置一个别名:
~ @ aliases['la'] = 'ls -a'
字符串形式建立的别名将自动转换为列表, 也即对象的智能性:
~ @ aliases['la'] = 'ls -a'
~ @ aliases['la']
['ls', '-a']
若要取消一个别名, 只需:
~
