eval
eval 的功能是将字符串作为代码来执行。
% str1=str2
% str2=abc
% eval echo \$$str1
abc
有一个 \ 和两个$。第二个$是和平常一样的意义,正常取str1的值,第一个$是转义,因为它要在 eval 执行的过程中取 str2 的值,不能现在就展开。
所以有了更好的写法:
% str1=str2
% str2=abc
% echo ${(P)str1}
abc
(P) 专门用于这种场景,不需要再去转义 $。
Socket 文件
UNIX domain socket 是比管道更先进的进程通信方法,是全双工的方式,并且稳定性更好。但性能比管道差一些,不过一般性能瓶颈都不会出现在这里,不用考虑性能问题。而且在一个 socket 文件上可以建立多个连接,更容易管理。另外如果通信方式从 socket 文件改成 TCP,只需要修改很少的代码(建立和关闭连接的代码稍微改一下),而从管道改成 TCP 则要麻烦很多。
所以建议用 zsh 写进程交互脚本的话,直接使用 socket 文件,而不是命名管道(匿名管道就能满足需求的简单场景忽略不计)。
Socket 文件的用法:
# 监听连接端
# 首先要加载 socket 模块
% zmodload zsh/net/socket
% zsocket -l test.sock
% listenfd=$REPLY
# 此处阻塞等待连接
% zsocket -a $listenfd
# 连接建立完成
% fd=$REPLY
% echo $fd
5
# 然后 $fd 就可读可写
% cat <&$fd
good
关闭连接:
# 发起连接端
# fd 是之前存放 fd 号的变量,不需要加 $
% exec {fd}>&-
# 监听连接端
% exec {listenfd}>&-
% exec {fd}>&-
# 删除 socket 文件即可,如果下次再使用会重新创建,该文件不能重复使用
% rm test.sock
TCP
使用 TCP 连接的方式和使用 socket 文件基本一样。
# 监听连接端
# 首先要加载 tcp 模块
% zmodload zsh/net/tcp
% ztcp -l 1234
% listenfd=$REPLY
# 此处阻塞等待连接
% ztcp -a $listenfd
# 连接建立完成
% fd=$REPLY
% echo $fd
3
# 然后 $fd 就可读可写
% cat <&$fd
good
关闭连接:
# 发起连接端
# fd 是之前存放 fd 号的变量
% ztcp -c $fd
# 监听连接端
% ztcp -c $listenfd
% ztcp -c $fd