You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 03:20:32