如何在Pharo中调用命令行工具?Mac平台实操需求求助
在Pharo中调用Mac命令行工具的实现方案
需求背景
我曾阅读UFFI相关书籍,但基础知识不足,现需要开发一款工具:选择包含文件的文件夹,将数据分组适配DVD容量、添加校验和与奇偶校验,最终从Pharo内完成DVD烧录。需在Mac系统中调用以下工具:
shasum:生成校验和diskutil list:列出磁盘信息hdiutil burn:烧录DVD
已尝试的UFFI代码
我尝试用UFFI调用shasum,代码如下:
shasum: filePath to: checksumFile ^ self ffiCall: #( int shasum(char * filepPath pathString, char * checksumFile) ) library: 'libcrypto.dylib'
同时我也在考虑采用LibC方案来调用命令行工具。
实用实现方案
方案一:直接调用系统命令(推荐)
无需纠结底层UFFI封装,Pharo可以直接执行终端命令,这比调用底层库更高效,也贴合命令行工具的使用场景。
1. 用LibC的system函数快速执行
通过LibC的system:方法直接执行命令,适合不需要捕获输出的场景:
"生成shasum并写入文件" generateShasumFor: filePath to: checksumFile | cmd | cmd := 'shasum ', filePath fullName, ' > ', checksumFile fullName. ^ LibC uniqueInstance system: cmd "烧录DVD" burnDVD: imagePath | cmd | cmd := 'hdiutil burn ', imagePath fullName. ^ LibC uniqueInstance system: cmd
如果需要获取命令的输出或错误信息,推荐用PipeableOSProcess:
"列出磁盘信息并获取输出" listDisks | output | output := PipeableOSProcess waitForCommand: 'diskutil list'. ^ { #stdout -> output output. #stderr -> output errorOutput } asDictionary
2. 用OSProcess包实现灵活进程控制
先安装OSProcess包:
Metacello new baseline: 'OSProcess'; repository: 'github://dtlewis290/OSProcess:master/repository'; load.
然后封装通用命令执行方法,方便获取完整执行结果:
runCommand: cmdStr | process | process := PipeableOSProcess command: cmdStr. process waitForExit. ^ { #exitCode -> process exitCode. #stdout -> process output. #stderr -> process errorOutput } asDictionary
调用示例:
shasumResult := self runCommand: 'shasum /path/to/file'. diskList := self runCommand: 'diskutil list'. burnResult := self runCommand: 'hdiutil burn /path/to/image.iso'.
方案二:修正UFFI调用(仅适合底层需求)
你之前的代码有误:shasum是终端命令,并非libcrypto.dylib中的函数。如果必须用底层库生成校验和,需要调用OpenSSL的SHA系列函数,示例如下(以SHA256为例):
首先定义LibCrypto类封装UFFI:
LibCrypto class >> SHA256_Init: ctx ^ self ffiCall: #( void SHA256_Init(void *ctx) ) library: 'libcrypto.dylib' LibCrypto class >> SHA256_Update: ctx data: buffer len: len ^ self ffiCall: #( void SHA256_Update(void *ctx, void *buffer, int len) ) library: 'libcrypto.dylib' LibCrypto class >> SHA256_Final: digest ctx: ctx ^ self ffiCall: #( void SHA256_Final(unsigned char *digest, void *ctx) ) library: 'libcrypto.dylib'
然后实现校验和生成:
computeSHA256For: filePath | file buffer ctx digest | file := FileStream readOnlyFileNamed: filePath fullName. buffer := ByteArray new: 1024. ctx := ByteArray new: 64. "SHA256_CTX的内存大小" LibCrypto SHA256_Init: ctx. [ file atEnd ] whileFalse: [ file readInto: buffer startingAt: 1 count: buffer size. LibCrypto SHA256_Update: ctx data: buffer len: file position - file previousPosition. ]. digest := ByteArray new: 32. LibCrypto SHA256_Final: digest ctx: ctx. file close. ^ digest hex asUppercase
此方案复杂度高,仅适合需要自定义校验逻辑的场景,不推荐用于常规命令调用。
方案选择建议
优先选直接调用系统命令的方案:
- 实现简单,不用深入底层FFI细节
- 复用系统工具的成熟功能,避免自己实现磁盘识别、烧录等复杂逻辑
- 调试方便,可先在终端验证命令有效性再移植到Pharo
内容的提问来源于stack exchange,提问作者pauel
相关产品推荐
相关产品推荐

