Skip to main content

babashkaprocess

Clojure library for spawning sub-processes and shell operations

来源信息

仓库
hugoduncan/library-skills
最近来源活动
2026年1月17日 13:40
检测到的 SKILL.md 语言
英语
星标
3
分支
0

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

文件资源管理器
3 个文件

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
babashka.process
description
Clojure library for spawning sub-processes and shell operations
# babashka.process A Clojure library for shelling out and spawning sub-processes. Wraps `java.lang.ProcessBuilder` with an ergonomic API supporting pipelines, streaming I/O, and process control. ## Overview babashka.process provides two main entry points: - `shell` - High-level convenience function with sensible defaults - `process` - Low-level function for fine-grained control Included in Babashka since v0.2.3. Also usable as a JVM library. **Repository:** https://github.com/babashka/process ## Installation ```clojure ;; deps.edn {:deps {babashka/process {:mvn/version "0.6.25"}}} ``` Built into Babashka - no installation needed for bb scripts. ## Core Concepts ### shell vs process | Aspect | `shell` | `process` | |--------|---------|-----------| | Blocking | Yes | No (returns immediately) | | Exit check | Throws on non-zero | No checking | | I/O default | `:inherit` (console) | Streams | | Tokenization | Auto-tokenizes first arg | Manual | Use `shell` for simple commands. Use `process` for pipelines, streaming, or async operations. ### Process Records Both functions return a record containing: - `:proc` - `java.lang.Process` instance - `:in` - Input stream (stdin) - `:out` - Output stream (stdout) - `:err` - Error stream (stderr) - `:cmd` - Command vector - `:prev` - Previous process (pipelines) Dereferencing (`@` or `deref`) waits for completion and adds `:exit`. ## API Reference ### shell High-level function for running external programs. ```clojure (require '[babashka.process :refer [shell]]) ;; Basic usage - tokenizes automatically (shell "ls -la") ;; Multiple arguments (shell "git" "commit" "-m" "message") ;; With options (shell {:dir "src"} "ls") ;; Capture output (-> (shell {:out :string} "echo hello") :out) ;; => "hello\n" ;; Continue on error (don't throw) (shell {:continue true} "ls nonexistent") ``` **Options:** - `:continue` - Don't throw on non-zero exit - All `process` options supported ### process Low-level function with no opinionated defaults. ```clojure (require '[babashka.process :refer [process]]) ;; Returns immediately (def p (process "sleep" "5")) ;; Deref to wait and get exit code (:exit @p) ;; Capture output (->> (process {:out :string} "ls") deref :out) ``` ### check Wait for process and throw on non-zero exit. ```clojure (require '[babashka.process :refer [process check]]) ;; Throws if ls fails (->> (process {:out :string} "ls") check :out) ;; Chain with process (-> (process "make") check) ``` ### sh Convenience wrapper defaulting `:out` and `:err` to `:string`. ```clojure (require '[babashka.process :refer [sh]]) (sh "ls" "-la") ;; => {:exit 0 :out "..." :err ""} ``` ### $ Macro for shell-like syntax with interpolation. ```clojure (require '[babashka.process :refer [$]]) (def file "README.md") ($ ls -la ~file) ;; With options via metadata (^{:out :string} $ echo hello) ``` ### tokenize Split string into argument vector. ```clojure (require '[babashka.process :refer [tokenize]]) (tokenize "ls -la") ;; => ["ls" "-la"] (tokenize "echo 'hello world'") ;; => ["echo" "hello world"] ``` ### alive? Check if process is running. ```clojure (require '[babashka.process :refer [process alive?]]) (def p (process "sleep" "10")) (alive? p) ;; => true ``` ### destroy / destroy-tree Terminate process. `destroy-tree` also kills descendants (JDK9+). ```clojure (require '[babashka.process :refer [process destroy destroy-tree]]) (def p (process "sleep" "100")) (destroy p) ;; Kill process and all children (destroy-tree p) ``` ### exec Replace current process image (GraalVM/Babashka only). ```clojure (require '[babashka.process :refer [exec]]) ;; Replaces bb process with ls (exec "ls" "-la") ``` ### pb / pipeline Create process builders for pipelines. ```clojure (require '[babashka.process :refer [pb pipeline]]) ;; JDK9+ pipeline (-> (pipeline (pb "cat" "file.txt") (pb "grep" "pattern") (pb "wc" "-l")) last deref :out slurp) ``` ## Options Reference ### I/O Options | Option | Values | Description | |--------|--------|-------------| | `:in` | stream, string, `:inherit` | Stdin source | | `:out` | `:string`, `:bytes`, `:inherit`, `:write`, `:append`, file | Stdout destination | | `:err` | Same as `:out`, plus `:out` to merge | Stderr destination | | `:in-enc` | charset | Input encoding | | `:out-enc` | charset | Output encoding | | `:err-enc` | charset | Error encoding | ### Process Options | Option | Description | |--------|-------------| | `:dir` | Working directory | | `:env` | Replace environment (map) | | `:extra-env` | Add to environment (map) | | `:inherit` | If true, inherit all streams | | `:cmd` | Command vector (overrides args) | | `:prev` | Previous process for piping | ### Hooks | Option | Description | |--------|-------------| | `:pre-start-fn` | Called before start with process info | | `:shutdown` | Called when child process ends | | `:exit-fn` | Called on exit (JDK11+) | ## Common Patterns ### Capture Output ```clojure ;; As string (-> (shell {:out :string} "date") :out str/trim) ;; As bytes (-> (shell {:out :bytes} "cat" "image.png") :out) ;; Merge stderr into stdout (shell {:err :out :out :string} "cmd") ``` ### Working Directory ```clojure (shell {:dir "/tmp"} "ls") ``` ### Environment Variables ```clojure ;; Add to environment (shell {:extra-env {"DEBUG" "1"}} "./script.sh") ;; Replace environment (shell {:env {"PATH" "/usr/bin"}} "ls") ``` ### Piping Processes ```clojure ;; Using threading (->> (process "cat" "file.txt") (process {:out :string} "grep" "pattern") deref :out) ;; Using pipeline (JDK9+) (-> (pipeline (pb "ls") (pb "grep" "clj")) last deref :out slurp) ``` ### Input to Process ```clojure ;; String input (-> (process {:in "hello\nworld" :out :string} "cat") deref :out) ;; File input (-> (process {:in (io/file "data.txt") :out :string} "wc") deref :out) ``` ### Close Stdin For processes that read stdin until EOF, close it immediately: ```clojure ;; Empty string - simplest approach (process {:in ""} "cmd") ;; Null device (process {:in null-file} "cmd") ;; Explicit close after start (let [p (process "cmd")] (.close (:in p)) p) ``` ### Streaming Output ```clojure (require '[clojure.java.io :as io]) (def p (process {:err :inherit} "bb" "-e" "(doseq [i (range)] (println i) (Thread/sleep 100))")) (with-open [rdr (io/reader (:out p))] (doseq [line (line-seq rdr)] (println "Got:" line))) ``` ### Interactive Process ```clojure (def p (process "cat")) (def w (io/writer (:in p))) (binding [*out* w] (println "hello") (println "world")) (.close w) (slurp (:out p)) ;; => "hello\nworld\n" ``` ### Write to File ```clojure ;; Overwrite (shell {:out :write :out-file "log.txt"} "ls") ;; Append (shell {:out :append :out-file "log.txt"} "date") ``` ### Discard Output ```clojure (require '[babashka.process :refer [shell null-file]]) (shell {:out null-file :err null-file} "noisy-command") ``` ### Timeout ```clojure (let [p (process "sleep" "100")] (when-not (deref p 1000 nil) (destroy-tree p) (println "Timed out"))) ``` ### Pre-start Hook ```clojure (shell {:pre-start-fn (fn [{:keys [cmd]}] (println "Running:" cmd))} "ls") ``` ## Error Handling ### Check Exit Code ```clojure ;; shell throws by default (try (shell "ls" "nonexistent") (catch Exception e (println "Failed:" (ex-message e)))) ;; Suppress with :continue (let [{:keys [exit]} (shell {:continue true} "ls" "nonexistent")] (when-not (zero? exit) (println "Command failed"))) ``` ### Process Errors ```clojure ;; Manual checking with process (let [{:keys [exit out err]} @(process {:out :string :err :string} "cmd")] (if (zero? exit) (println "Success:" out) (println "Error:" err))) ``` ### Capture Stderr ```clojure
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看