### start Source: https://github.com/babashka/process/blob/master/API.md Takes a process builder and starts the process, returning a process record. ```APIDOC ## `start` ### Description Takes a process builder, calls start and returns a process (as record). ``` -------------------------------- ### Start a Process from a Process Builder Source: https://github.com/babashka/process/blob/master/API.md The `start` function takes a process builder and initiates the process, returning a process record. ```clojure (start pb) ``` -------------------------------- ### Build Minimal Windows Executable with Go Source: https://github.com/babashka/process/blob/master/test-resources/README.md Use this command to build a basic Windows executable from Go source. Ensure Go is installed and you are in the directory containing the Go source file. ```shell GOOS=windows GOARCH=amd64 go build -o print-dirs.exe print-dirs.go ``` -------------------------------- ### Execute Command with Stdin Input Source: https://github.com/babashka/process/blob/master/README.md Demonstrates passing input to a command via stdin using `sh` and the `:in` option. The example uses `clj-kondo` to lint from stdin. ```clojure (-> (sh {:in "(inc)"} "clj-kondo --lint -") :out) ``` -------------------------------- ### Build Windows Executable Using Docker Source: https://github.com/babashka/process/blob/master/test-resources/README.md This command builds a Windows executable and compresses it using UPX within a Docker container, avoiding local installation of Go and UPX. It mounts the current directory as a volume. ```shell docker run --rm \ -v "$PWD":/src \ -w /src \ devopsworks/golang-upx:latest \ bash -c 'GOOS=windows GOARCH=amd64 \ go build -ldflags "-s -w" -o print-dirs.exe print-dirs.go && upx --ultra-brute print-dirs.exe' ``` -------------------------------- ### Capture Process Output to String Source: https://github.com/babashka/process/blob/master/README.md Use `with-out-str` to capture the output of a process. This example pipes the string 'foo' into a 'cat' process and captures its output. ```clojure user=> (with-out-str (check (process {:in "foo" :out *out*} "cat"))) "foo" ``` -------------------------------- ### Explicit OS-Level Pipelines with `pipeline` and `pb` Source: https://context7.com/babashka/process/llms.txt `pipeline` and `pb` allow building and executing OS-level pipelines, avoiding buffering issues by using JDK 9+ `ProcessBuilder/startPipeline`. `pb` creates a process builder record without starting the process. ```clojure (require '[babashka.process :refer [pipeline pb check]]) ;; Create a pipeline and read the right-most output (-> (pipeline (pb "ls") (pb "grep" ".md") (pb {:out :string} "sort")) last deref :out) ``` ```clojure ;; Check every process in the pipeline for errors (run! check (pipeline (pb "ls") (pb "cat"))) ``` ```clojure ;; Retrieve pipeline from an already-running right-most process (let [p (pipeline (pb "ls") (pb {:out :string} "cat"))] (mapv :cmd p)) ``` ```clojure ;; Real-time grep on a tail -f stream (JDK9+) (pipeline (pb "tail" "-f" "log.txt") (pb {:out :inherit} "grep" "ERROR")) ``` -------------------------------- ### Override Global Defaults with `*defaults*` Source: https://context7.com/babashka/process/llms.txt `*defaults*` is a dynamic var for default options. Use `alter-var-root` for permanent overrides or `binding` for temporary ones. This example shows global command logging. ```clojure (require '[babashka.process :refer [process shell *defaults*]]) ;; Permanently add :pre-start-fn for global command logging (alter-var-root #'*defaults* assoc :pre-start-fn (fn [{:keys [cmd]}] (binding [*out* *err*] (println "[CMD]" (clojure.string/join " " cmd))))) (shell "ls -la") ; [CMD] ls -la ; ... directory listing ... ;; Temporarily override defaults for a block (binding [*defaults* (assoc *defaults* :dir "/tmp")] (-> @(process {:out :string} "ls") :out println)) ``` -------------------------------- ### Check Pipeline for Non-zero Exit Codes Source: https://github.com/babashka/process/blob/master/README.md Illustrates using `run!` with `check` to verify that all processes in a pipeline have exited successfully (zero exit code). An example of an error is shown. ```clojure (run! check (pipeline (pb "ls foo") (pb "cat"))) ;=> Execution error (ExceptionInfo) at babashka.process/check (process.clj:37). l s: foo: No such file or directory ``` -------------------------------- ### Run JVM tests with default Clojure Source: https://github.com/babashka/process/blob/master/doc/dev.md Execute JVM tests using the default Clojure version. This task checks the first argument; if it starts with `:clj-`, it's treated as a `deps.edn` alias. ```Shell $ bb test:jvm ``` -------------------------------- ### Check Process Exit Code and Capture Output Source: https://github.com/babashka/process/blob/master/README.md The `check` function waits for a process to finish and returns it, throwing an exception for non-zero exit codes. This example captures stdout as a string and checks for a successful 'ls' command. ```clojure user=> (-> (process {:out :string} "ls") check :out str/split-lines first) "API.md" ``` -------------------------------- ### Combine babashka.process with Promesa on JVM Source: https://github.com/babashka/process/blob/master/README.md On the JVM, you can combine babashka.process with Promesa to handle process termination asynchronously. This example defines a `process` function that returns a promise resolved upon termination, rejecting if the exit code is non-zero. Requires `:exit-fn` from version `0.2.10`. ```clojure (require '[babashka.process :as proc] '[promesa.core :as prom]) (defn process "Returns promise that will be resolved upon process termination. The promise is rejected when the exit code is non-zero." [opts & cmd] (prom/create (fn [resolve reject] (let [exit-fn (fn [response] (let [{:keys [exit] :as r} response] (if (zero? exit) (resolve r) (reject r))))] (apply proc/process (assoc opts :exit-fn exit-fn) cmd))))) (prom/let [ls (process {:out :string :err :inherit} "ls") ls-out (:out ls)] (prn ls-out)) ``` -------------------------------- ### Access Right-most Process in Pipeline Source: https://github.com/babashka/process/blob/master/README.md Shows how to get the last process in a pipeline using the `last` function and access its output. ```clojure (-> (pipeline (pb "ls") (pb "cat")) last :out slurp) ;=> "LICENSE\nREADME.md\ndeps.edn\nsrc\ntest\n..." ``` -------------------------------- ### Threaded Process Piping Source: https://github.com/babashka/process/blob/master/README.md Uses the thread-first macro `->` to pipe the output of a 'ls' process to a 'grep README' process, then dereferences the result to get the output string. ```clojure user=> (-> (process "ls") (process {:out :string} "grep README") deref :out) "README.md\n" ``` -------------------------------- ### Create Pipeline with -> and pb Source: https://github.com/babashka/process/blob/master/README.md Demonstrates creating a pipeline using both the `->` macro and `pb` function. Requires importing `pipeline`, `pb`, `process`, and `check` from `babashka.process`. ```clojure (require '[babashka.process :refer [pipeline pb process check]]) nil (mapv :cmd (pipeline (-> (process "ls") (process "cat")))) ;=> [["ls"] ["cat"]] (mapv :cmd (pipeline (pb "ls") (pb "cat"))) ;=> [["ls"] ["cat"]] ``` -------------------------------- ### Print Commands Before Execution Source: https://github.com/babashka/process/blob/master/README.md Use the `:pre-start-fn` option to log commands before they are executed. This is useful for debugging and understanding process flow. ```clojure (require '[babashka.process :refer [process]]) (doseq [file ["LICENSE" "CHANGELOG.md"]] (-> (process {:out :string :pre-start-fn #(apply println "Running" (:cmd %))} "head" "-1" file) deref :out println)) ``` -------------------------------- ### Launch PowerShell Script on Windows Source: https://github.com/babashka/process/blob/master/README.md Demonstrates how to launch a Windows `.ps1` script using `p/shell` by explicitly calling `powershell.exe`. ```clojure (p/shell "powershell.exe -File .\a.ps1") ``` -------------------------------- ### Dereference Process Exit Code Source: https://github.com/babashka/process/blob/master/README.md Use `deref` to wait for a process to complete and retrieve its exit code. This example shows checking the exit code of 'ls foo'. ```clojure user=> (-> (process "ls foo") deref :exit) 1 ``` -------------------------------- ### Create a Child Process with Options Source: https://github.com/babashka/process/blob/master/API.md Use `process` to create a child process. It accepts a command and an optional map of options for input/output redirection, environment, working directory, and more. The function returns a record containing the process instance and its streams. ```clojure (process opts? & args) ``` -------------------------------- ### Execute Shell Command with Output Redirection and Arguments Source: https://github.com/babashka/process/blob/master/API.md Pass an options map to `shell` to configure behavior like output redirection. Additional arguments are appended after the tokenized command. ```clojure (shell {:out "/tmp/log.txt"} "git commit -m" "WIP") ``` -------------------------------- ### Execute Shell Commands with Options Source: https://github.com/babashka/process/blob/master/README.md Use `shell` to execute commands. Options like `:dir` can be passed as a map. The first string argument is automatically tokenized. ```clojure (require '[babashka.process :refer [shell process exec]]) (shell "ls" "-la") ;; no options (shell "ls -la" "dir") ;; first string is tokenized automatically, more strings may be provided (shell {:dir "target"} "ls" "-la") ``` -------------------------------- ### Create Pipeline with pipeline and pb (JDK9+) Source: https://github.com/babashka/process/blob/master/README.md Provides an alternative method to create pipelines using `pipeline` with `pb` for scenarios where direct piping is preferred over `->`. This method is available on JDK9 or higher. ```clojure (pipeline (pb "tail" "-f" "log.txt") (pb "cat") (pb {:out :inherit} "grep" "5")) ``` -------------------------------- ### Build Smaller Windows Executable with Go Source: https://github.com/babashka/process/blob/master/test-resources/README.md This command builds a smaller Windows executable by stripping debug information using Go's linker flags. This is useful for reducing binary size. ```shell GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -o print-dirs.exe print-dirs.go ``` -------------------------------- ### Create Process Pipeline (Clojure) Source: https://github.com/babashka/process/blob/master/API.md Returns processes for a pipe created with `->` or creates a pipeline from multiple process builders. Requires JDK9+ for multiple builders. ```clojure (pipeline proc) ``` ```clojure (pipeline pb & pbs) ``` -------------------------------- ### Pretty-Print Process Records Source: https://context7.com/babashka/process/llms.txt Require `babashka.process.pprint` to register a `clojure.pprint` method for the `Process` record, resolving multimethod ambiguity. ```clojure (require '[babashka.process :refer [process]] '[babashka.process.pprint] '[clojure.pprint :as pprint]) (pprint/pprint (process "ls")) ; {:proc #object[java.lang.ProcessImpl 0x... "Process[pid=1234, exitValue=\"not exited\"]"], ; :exit nil, ; :in #object[java.io.OutputStream ...], ; :out #object[java.io.InputStream ...], ; :err #object[java.io.InputStream ...], ; :cmd ["ls"], ; :prev nil} ``` -------------------------------- ### Feed Input to a Running Process Source: https://github.com/babashka/process/blob/master/README.md Demonstrates feeding input to a 'cat' process asynchronously. It writes 'hello\n' to the process's stdin, closes it, and then reads the output. ```clojure (ns cat-demo (:require [babashka.process :refer [process alive?]] [clojure.java.io :as io])) (def catp (process "cat")) (alive? catp) ;; true (def stdin (io/writer (:in catp))) (binding [*out* stdin] (println "hello")) (.close stdin) (slurp (:out catp)) ;; "hello\n" (:exit @catp) ;; 0 (alive? catp) ;; false ``` -------------------------------- ### Pretty-print Process Output with babashka.process.pprint Source: https://github.com/babashka/process/blob/master/README.md When pretty-printing a process, an exception may occur due to conflicting implementations. Require the `babashka.process.pprint` namespace to define a specific `pprint` implementation for `Process` records. ```clojure user=> (require '[babashka.process :refer [process]]) nil user=> (require '[clojure.pprint :as pprint]) nil user=> (pprint/pprint (process "ls")) Execution error (IllegalArgumentException) at user/eval257 (REPL:1). Multiple methods in multimethod 'simple-dispatch' match dispatch value: class babashka.process.Process -> interface clojure.lang.IDeref and interface clojure.lang.IPersistentMap, and neither is preferred ``` ```clojure user=> (require '[babashka.process.pprint]) nil user=> (pprint/pprint (process "ls")) {:proc #object[java.lang.ProcessImpl 0x1d61a348 "Process[pid=43771, exitValue=\"not exited\"]"], :exit nil, ... ``` -------------------------------- ### Process Input/Output with `process` Source: https://github.com/babashka/process/blob/master/README.md The `process` function can be used to pipe data into a process, demonstrated here with `cat`. ```clojure (process {:in "hello"} "cat") ``` -------------------------------- ### Process and Capture Directory Listing Source: https://github.com/babashka/process/blob/master/README.md Captures the first two lines of the output from an 'ls' command into a string. Requires `str/split-lines` for processing. ```clojure user=> (->> (with-out-str (check (process {:out *out*} "ls"))) str/split-lines (take 2)) ("API.md" "CHANGELOG.md") ``` -------------------------------- ### Execute Command and Replace Process (Clojure) Source: https://github.com/babashka/process/blob/master/API.md Replaces the current process with a new one. Only works in GraalVM native images (including babashka). Supports options like `:arg0`, `:cmd`, `:env`, etc. ```clojure (exec opts? & args) ``` -------------------------------- ### Default Options for Processes (*defaults*) Source: https://github.com/babashka/process/blob/master/API.md The `*defaults*` dynamic var holds overridable default options for process execution. Use `alter-var-root` for permanent changes or `binding` for temporary modifications. -------------------------------- ### Shrink Executable Size with UPX Source: https://github.com/babashka/process/blob/master/test-resources/README.md After building an executable, UPX can be used to further compress its size. This command applies ultra-brute compression. ```shell upx --ultra-brute print-dirs.exe ``` -------------------------------- ### JDK8 Pipeline Solution with IO/Reader Source: https://github.com/babashka/process/blob/master/README.md A workaround for creating pipelines on JDK8 or lower, which involves manually reading output line by line from one process and piping it to another using `clojure.java.io` and `binding`. ```clojure (require '[clojure.java.io :as io]) nil (def tail (process {:err :inherit} "tail" "-f" "log.txt")) (def cat-and-grep (-> (process {:err :inherit} "cat") (process {:out :inherit :err :inherit} "grep 5"))) (binding [*in* (io/reader (:out tail)) *out* (io/writer (:in cat-and-grep))] (loop [] (when-let [x (read-line)] (println x) (recur)))) ``` -------------------------------- ### Create a Child Process with Parsed Arguments Source: https://github.com/babashka/process/blob/master/API.md Use `process*` when you already have parsed arguments from `parse-args`. This function is similar to `process` but expects a map containing `prev`, `cmd`, and `opts`. ```clojure (process* {:keys [prev cmd opts]}) ``` -------------------------------- ### `pipeline` and `pb` — Explicit OS-Level Pipelines Source: https://context7.com/babashka/process/llms.txt `pb` creates a process builder, and `pipeline` connects multiple process builders to form a shell pipeline. This method is preferred over simple threading for complex pipelines to avoid buffering issues. ```APIDOC ## `pipeline` and `pb` — Explicit OS-Level Pipelines `pb` builds a process-builder record without starting a process. `pipeline` connects multiple `pb` records via `ProcessBuilder/startPipeline` (JDK 9+), which avoids the buffering issues that can arise when chaining with `->`. ```clojure (require '[babashka.process :refer [pipeline pb check]]) ;; Create a pipeline and read the right-most output (-> (pipeline (pb "ls") (pb "grep" ".md") (pb {:out :string} "sort")) last deref :out) ; => "API.md\nCHANGELOG.md\nREADME.md\n" ;; Check every process in the pipeline for errors (run! check (pipeline (pb "ls") (pb "cat"))) ;; Retrieve pipeline from an already-running right-most process (let [p (pipeline (pb "ls") (pb {:out :string} "cat"))] (mapv :cmd p)) ; => [[ "ls" ] [ "cat" ]] ;; Real-time grep on a tail -f stream (JDK9+) (pipeline (pb "tail" "-f" "log.txt") (pb {:out :inherit} "grep" "ERROR")) ``` ``` -------------------------------- ### Run babashka process tests Source: https://github.com/babashka/process/blob/master/doc/dev.md Use this command to run all babashka.process tests. It executes `run_exec.clj` through bb. ```Shell $ bb test:bb --var "babashka.process-test/tokenize-test" ``` -------------------------------- ### Run a Command with Inherited I/O using `shell` Source: https://context7.com/babashka/process/llms.txt Use `shell` for common command execution. It streams output in real-time and throws an exception on non-zero exit codes. The first string argument is automatically tokenized. ```clojure (require '[babashka.process :refer [shell]] '[clojure.string :as str]) ;; Basic usage — output streams directly to console (shell "ls -la") ``` ```clojure ;; Capture stdout as a string; capture stderr separately (let [{:keys [out err exit]} (shell {:out :string :err :string} "git" "log" "--oneline" "-5")] (println "exit:" exit) (println "stdout:" out) (println "stderr:" err)) ``` ```clojure ;; Suppress the exception on non-zero exit and inspect :exit yourself (let [{:keys [exit]} (shell {:continue true} "ls" "/no/such/dir")] (println "exit code:" exit)) ; => exit code: 1 ``` ```clojure ;; Change working directory and add extra environment variable (shell {:dir "/tmp" :extra-env {"MY_VAR" "hello"}} "bash" "-c" "echo $MY_VAR") ``` ```clojure ;; Write stdout directly to a file (shorthand string path) (shell {:out "/tmp/listing.txt"} "ls -la") ``` ```clojure ;; Apply command-line args forwarded from a babashka script (apply shell "git log --oneline" *command-line-args*) ``` -------------------------------- ### Handle Non-existent File Error with Check Source: https://github.com/babashka/process/blob/master/README.md Demonstrates `check` throwing an exception when a command fails due to a non-existent file. The error message indicates 'ls: foo: No such file or directory'. ```clojure user=> (-> (process {:out :string} "ls foo") check :out str/split-lines first) Execution error (ExceptionInfo) at babashka.process/check (process.clj:74). ls: foo: No such file or directory ``` -------------------------------- ### Low-Level Async Process Creation with `process` Source: https://context7.com/babashka/process/llms.txt Use `process` for asynchronous I/O, streaming, or when full control over streams is needed. It returns immediately, and dereferencing the result blocks until the process finishes. ```clojure (require '[babashka.process :refer [process check]] '[clojure.java.io :as io] '[clojure.string :as str]) ;; Deref to wait and get exit code (-> (process "ls" "nonexistent") deref :exit) ; => 1 ``` ```clojure ;; Collect stdout into a string (must deref before accessing :out) (-> @(process {:out :string} "ls") :out str/split-lines first) ; => "API.md" ``` ```clojure ;; Collect raw bytes (-> @(process {:out :bytes} "head" "-c" "8" "/dev/urandom") :out seq) ``` ```clojure ;; Pipe a string as stdin (-> @(process {:in "hello world\n" :out :string} "cat") :out) ; => "hello world\n" ``` ```clojure ;; Pipe from one process output stream to another (let [ls-proc (process "ls") grep-proc (process {:in (:out ls-proc) :out :string} "grep" ".md")] (-> @grep-proc :out str/split-lines)) ; => ["API.md" "CHANGELOG.md" "README.md"] ``` ```clojure ;; Log the command before it runs with :pre-start-fn (-> (process {:out :string :pre-start-fn #(apply println "Running:" (:cmd %))} "head" "-1" "README.md") deref :out) ; Running: head -1 README.md ; => "# process\n" ``` ```clojure ;; Write output to a file, appending (require '[clojure.java.io :as io]) @(process {:out :append :out-file (io/file "/tmp/out.txt")} "date") ``` ```clojure ;; Discard stderr @(process {:err :discard :out :string} "ls" "/tmp") ``` ```clojure ;; Register a shutdown hook to kill the process on JVM exit (def p (process {:shutdown babashka.process/destroy-tree} "tail" "-f" "/var/log/syslog")) ``` -------------------------------- ### Execute Shell Command with Default I/O Source: https://github.com/babashka/process/blob/master/API.md Use `shell` for convenience when executing external commands. It inherits I/O and throws on non-zero exit codes by default. The first argument is tokenized. ```clojure (shell "ls -la") ``` -------------------------------- ### Create Process Builder (Clojure) Source: https://github.com/babashka/process/blob/master/API.md Returns a process builder record. Used for constructing process pipelines. ```clojure (pb & args) ``` -------------------------------- ### Integrate with Promesa for Process Promises (JVM) Source: https://context7.com/babashka/process/llms.txt Wrap `process` with Promesa promises using the `:exit-fn` hook. The promise resolves on zero exit and rejects on non-zero exit. Requires version 0.2.10+, JDK 11+. ```clojure (require '[babashka.process :as proc] '[promesa.core :as prom]) (defn process-promise "Returns a promise resolved on zero exit, rejected on non-zero exit." [opts & cmd] (prom/create (fn [resolve reject] (let [exit-fn (fn [{:keys [exit] :as result}] (if (zero? exit) (resolve result) (reject result)))] (apply proc/process (assoc opts :exit-fn exit-fn) cmd))))) @(prom/let [result (process-promise {:out :string :err :inherit} "ls") lines (clojure.string/split-lines (:out result))] (println "Files:" (count lines) "total") lines) ; Files: 8 total ; => ["API.md" "CHANGELOG.md" ...] ``` -------------------------------- ### Execute a simple shell command Source: https://github.com/babashka/process/blob/master/README.md Executes a command and streams its output to stdout and stderr. The first argument is tokenized automatically. ```clojure user=> (shell "ls" "-la") total 144 drwxr-xr-x@ 22 borkdude staff 704 Dec 4 13:39 . drwxr-xr-x@ 75 borkdude staff 2400 Dec 3 14:18 .. drwxr-xr-x@ 4 borkdude staff 128 Mar 10 2022 .circleci drwxr-xr-x@ 5 borkdude staff 160 Mar 10 2022 .clj-kondo drwxr-xr-x@ 50 borkdude staff 1600 Dec 3 20:55 .cpcache ``` -------------------------------- ### Run JVM tests with all Clojure versions Source: https://github.com/babashka/process/blob/master/doc/dev.md Execute JVM tests across all supported Clojure versions by using the `:clj-all` alias. This ensures compatibility with different Clojure environments. ```Shell $ bb test:jvm :clj-all ``` -------------------------------- ### Pipe Output Between Shell Commands Source: https://github.com/babashka/process/blob/master/README.md Demonstrates piping the output of one `shell` command ('ls') to the input of another ('grep md'). The first command must specify `{:out :string}` to capture its output. ```clojure user=> (let [ls-result (shell {:out :string} "ls")] (shell {:in (:out ls-result)} "grep md")) API.md CHANGELOG.md README.md ... ``` -------------------------------- ### `exec` — Replace Current Process (GraalVM / Babashka) Source: https://context7.com/babashka/process/llms.txt `exec` replaces the current process with a new one using the `exec` syscall. This is primarily useful in GraalVM native images and babashka. On the JVM, it falls back to launching a child process. ```APIDOC ## `exec` — Replace Current Process (GraalVM / Babashka) `exec` replaces the current process image using a Unix `exec` syscall. It is only effective in GraalVM native images (including babashka). On the JVM it falls back to launching a child process. ```clojure (require '[babashka.process :refer [exec]]) ;; Replace the babashka process with bash (exec "bash") ;; Override arg0 (the executable name seen by the child) (exec {:arg0 "my-app"} "bash" "--norc") ;; Pass extra environment variables (exec {:extra-env {"APP_ENV" "production"}} "node" "server.js") ``` ``` -------------------------------- ### Execute Commands with Extra Environment Variables Source: https://github.com/babashka/process/blob/master/README.md Use `exec` to run a command, with the ability to set extra environment variables using `:extra-env`. ```clojure (exec {:extra-env {"FOO" "BAR"}} "bash") ``` -------------------------------- ### Run JVM tests with Clojure 1.9 Source: https://github.com/babashka/process/blob/master/doc/dev.md Run JVM tests specifically with Clojure version 1.9. This is achieved by passing `:clj-1.9` as an argument to the `test:jvm` task. ```Shell $ bb test:jvm :clj-1.9 ``` -------------------------------- ### Replace Current Process with `exec` Source: https://context7.com/babashka/process/llms.txt `exec` replaces the current process with a new one using a Unix `exec` syscall. This is effective in GraalVM native images and babashka; on JVM it launches a child process. ```clojure (require '[babashka.process :refer [exec]]) ;; Replace the babashka process with bash (exec "bash") ``` ```clojure ;; Override arg0 (the executable name seen by the child) (exec {:arg0 "my-app"} "bash" "--norc") ``` ```clojure ;; Pass extra environment variables (exec {:extra-env {"APP_ENV" "production"}} "node" "server.js") ``` -------------------------------- ### Append Process Output to a File Source: https://github.com/babashka/process/blob/master/README.md Appends the output of an 'ls' command to an existing file '/tmp/out.txt'. Uses `{:out :append :out-file ...}`. ```clojure user=> (do @(process {:out :append :out-file (io/file "/tmp/out.txt")} "ls") nil) nil user=> (slurp "/tmp/out.txt") "CHANGELOG.md\nLICENSE\nREADME.md..." ``` -------------------------------- ### `$` macro Source: https://github.com/babashka/process/blob/master/API.md A convenience macro that simplifies calling the `process` function. It accepts command arguments as varargs and supports options passed via metadata or as a map. It also handles interpolation using `~`. ```APIDOC ## `$` macro ### Description Convenience macro around `process`. Takes command as varargs. Options can be passed via metadata on the form or as a first map arg. Supports interpolation via `~`. ### Syntax ```clojure ($ opts? & args) ``` ``` -------------------------------- ### pipeline Source: https://github.com/babashka/process/blob/master/API.md Constructs or returns process pipelines. It can create a pipeline from multiple process builders or return a vector of processes from a `->` pipe. ```APIDOC ## `pipeline` ### Description Returns the processes for one pipe created with `->` or creates a pipeline from multiple process builders. - When passing a process, returns a vector of processes of a pipeline created with `->` or `pipeline`. - When passing two or more process builders created with `pb`: creates a pipeline as a vector of processes (JDK9+ only). Also see [Pipelines](/README.md#pipelines). ### Signatures ```clojure (pipeline proc) (pipeline pb & pbs) ``` ``` -------------------------------- ### Convenience Macro for Process Execution ($) Source: https://github.com/babashka/process/blob/master/API.md The `$` macro simplifies shelling out by taking the command as varargs. Options can be provided via metadata or as the first map argument. It supports interpolation using `~`. ```clojure ($ opts? & args) ``` -------------------------------- ### Execute command with dynamic arguments Source: https://github.com/babashka/process/blob/master/README.md Applies a list of arguments to the shell command, useful when arguments are provided dynamically, such as from the command line. ```clojure (apply shell "ls -la" *command-line-args*) ``` -------------------------------- ### Redirect Process Output to a File Source: https://github.com/babashka/process/blob/master/README.md Writes the output of an 'ls' command to a file named '/tmp/out.txt'. Requires `clojure.java.io` for file handling. The `do` form with `nil` suppresses the return value. ```clojure user=> (require '[clojure.java.io :as io]) nil user=> (do @(process {:out :write :out-file (io/file "/tmp/out.txt")} "ls") nil) nil user=> (slurp "/tmp/out.txt") "CHANGELOG.md\nLICENSE\nREADME.md..." ``` -------------------------------- ### Execute Shell Command and Capture Output Source: https://github.com/babashka/process/blob/master/API.md Use `sh` as a convenience function similar to `clojure.java.shell/sh`. It defaults `:out` and `:err` to `:string` and blocks until the process completes. The exit code is not checked by default; use `check` for that. ```clojure (sh opts? & args) ``` -------------------------------- ### Parse Process Arguments (Clojure) Source: https://github.com/babashka/process/blob/master/API.md Parses arguments for the `process` function into a map containing `:prev`, `:cmd`, and `:opts`. Bridges legacy and newer argument syntaxes. ```clojure (parse-args args) ``` -------------------------------- ### pb Source: https://github.com/babashka/process/blob/master/API.md Returns a process builder record, which can be used to construct process pipelines. ```APIDOC ## `pb` ### Description Returns a process builder (as record). ### Signature ```clojure (pb & args) ``` ``` -------------------------------- ### Execute command with additional arguments Source: https://github.com/babashka/process/blob/master/README.md Provides additional arguments to the shell command. This is useful for specifying paths or other parameters. ```clojure user=> (shell "ls -la" "src" "test") src: total 0 drwxr-xr-x@ 3 borkdude staff 96 Mar 10 2022 . drwxr-xr-x@ 22 borkdude staff 704 Dec 4 14:13 .. drwxr-xr-x@ 4 borkdude staff 128 Dec 4 14:01 babashka test: total 0 drwxr-xr-x@ 3 borkdude staff 96 Mar 10 2022 . drwxr-xr-x@ 22 borkdude staff 704 Dec 4 14:13 .. drwxr-xr-x@ 3 borkdude staff 96 Dec 4 14:01 babashka ``` -------------------------------- ### babashka.process/process Source: https://github.com/babashka/process/blob/master/API.md Creates a child process with specified options. It returns a record containing the Java Process instance, its streams, command, and previous process in a pipeline. The returned record can be dereferenced to wait for process completion and retrieve the exit code. ```APIDOC ## `process` ### Description Creates a child process. Takes a command (vector of strings or objects that will be turned into strings) and optionally a map of options. ### Returns A record with: - `:proc`: an instance of `java.lang.Process` - `:in`, `:err`, `:out`: the process's streams. Slurping these streams will block until the process is finished. - `:cmd`: the command that was passed to create the process. - `:prev`: previous process record in case of a pipeline. ### Supported options: - `:cmd`: A vector of strings. Overrides the variadic `args` argument. - `:in`, `:out`, `:err`: Objects compatible with `clojure.java.io/copy`. May be set to `:inherit` for redirecting to the parent process's corresponding stream. Supports `:string` or `:bytes` for `:out` and `:err` to write to a string or byte array (requires dereferencing the process record first). Can be set to `:discard` to discard output. Can be redirected to `:out` by specifying `:err :out`. Can be set to a `java.io.File` object or keywords like `:write` or `:append` with an additional `:out-file`/`:err-file` for file operations. - `:prev`: Output from `:prev` will be piped to the input of this process. Overrides `:in`. - `:inherit`: If true, sets `:in`, `:out`, and `:err` to `:inherit`. - `:dir`: Working directory. - `:env`, `:extra-env`: A map of environment variables. - `:escape`: Function applied to each stringified argument. Defaults to prepending a backslash before a double quote on Windows, and `identity` on other OSs. - `:pre-start-fn`: A function called with process info just before the process is started. Useful for debugging. - `:shutdown`: Shutdown hook, executed when the child process ends. Typically used with `destroy` or `destroy-tree`. - `:exit-fn`: A function executed upon exit, receiving the process map. Only supported in JDK11+. ``` -------------------------------- ### Collect Stdout as Byte Array Source: https://github.com/babashka/process/blob/master/README.md Collects stdout as a byte array using `{:out :bytes}`. Requires dereferencing the process to ensure the output is finalized. ```clojure user=> (-> @(process {:out :bytes} "head -c 10 /dev/urandom") :out seq) (119 -43 -68 -64 -16 -56 32 45 86 56) ``` -------------------------------- ### `tokenize` — Shell-Style String Tokenization Source: https://context7.com/babashka/process/llms.txt `tokenize` parses a command string into a vector of arguments, correctly handling quotes and escape characters as a shell would. ```APIDOC ## `tokenize` — Shell-Style String Tokenization `tokenize` splits a shell-like command string into a vector of argument strings, respecting single- and double-quoted segments and backslash escapes. ```clojure (require '[babashka.process :refer [tokenize]]) (tokenize "ls -la") ; => ["ls" "-la"] (tokenize "echo 'hello world'") ; => ["echo" "hello world"] (tokenize "git commit -m \"fix bug\"") ; => ["git" "commit" "-m" "fix bug"] (tokenize "a\\ b c") ; => ["a\\ b" "c"] ``` ``` -------------------------------- ### Pipe Process Output to Another Process Source: https://github.com/babashka/process/blob/master/README.md Connects the stdout of a 'ls' process to the stdin of a 'cat' process, with 'cat' outputting directly to the console. The `nil` at the end is to suppress the return value of the last expression. ```clojure user=> (let [stream (-> (process "ls") :out)] @(process {:in stream :out :inherit} "cat") nil) API.md CHANGELOG.md LICENSE README.md ... ``` -------------------------------- ### babashka.process/process* Source: https://github.com/babashka/process/blob/master/API.md A variant of `process` that accepts pre-parsed arguments, typically the result from `parse-args`. ```APIDOC ## `process*` ### Description Same as with `process` but called with parsed arguments (the result from `parse-args`). ``` -------------------------------- ### Collect Stdout as String Source: https://github.com/babashka/process/blob/master/README.md Collects stdout into a string using `{:out :string}`. Requires dereferencing the process to ensure the output is finalized. ```clojure user=> (-> @(process {:out :string} "ls") :out str/split-lines first) "API.md" ``` -------------------------------- ### parse-args Source: https://github.com/babashka/process/blob/master/API.md Parses arguments intended for the `process` function into a structured map containing previous process, command, and options. ```APIDOC ## `parse-args` ### Description Parses arguments to `process` to map with: * `:prev`: a (previous) process whose output is piped into the current process * `:cmd`: a vector of command line argument strings * `:opts`: options map Note that this function bridges the legacy `[cmds ?opts]` syntax to the newer recommended syntax `[?opts & args]` and therefore looks unnecessarily complex. ### Signature ```clojure (parse-args args) ``` ``` -------------------------------- ### `alive?` — Check Process Liveness Source: https://context7.com/babashka/process/llms.txt `alive?` checks if a process is currently running and returns `true` if it is, `false` otherwise. It's useful for monitoring process status. ```APIDOC ## `alive?` — Check Process Liveness Returns `true` if a process record is still running, `false` otherwise. ```clojure (require '[babashka.process :refer [process alive?]] '[clojure.java.io :as io]) (def catp (process "cat")) (alive? catp) ; => true (let [w (io/writer (:in catp))] (binding [*out* w] (println "hello")) (.close w)) (slurp (:out catp)) ; => "hello\n" (:exit @catp) ; => 0 (alive? catp) ; => false ``` ``` -------------------------------- ### Capture stdout as string Source: https://github.com/babashka/process/blob/master/README.md Captures the standard output of a command as a string using the `:out :string` option. Useful for processing command output programmatically. ```clojure user=> (-> (shell {:out :string} "ls -la") :out str/split-lines first) "total 144" ``` -------------------------------- ### Check Process Liveness with `alive?` Source: https://context7.com/babashka/process/llms.txt `alive?` returns `true` if a process record is still running and `false` otherwise. It's useful for monitoring process status. ```clojure (require '[babashka.process :refer [process alive?]] '[clojure.java.io :as io]) (def catp (process "cat")) (alive? catp) ; => true (let [w (io/writer (:in catp))] (binding [*out* w] (println "hello")) (.close w)) (slurp (:out catp)) ; => "hello\n" (:exit @catp) ; => 0 (alive? catp) ; => false ``` -------------------------------- ### Execute Shell Command with sh Source: https://github.com/babashka/process/blob/master/README.md The `sh` function is a convenience wrapper around `process` that defaults `:out` and `:err` to `:string` and blocks execution until completion, similar to `clojure.java.shell/sh`. ```clojure (def config {:output {:format :edn}}) (-> (sh ["clj-kondo" "--lint" "src"]) :out slurp edn/read-string) ``` -------------------------------- ### null-file Source: https://github.com/babashka/process/blob/master/API.md Represents a null file, often used for redirecting output or input to nowhere. ```APIDOC ## `null-file` ### Description Represents a null file. ### Signature ```clojure (null-file) ``` ``` -------------------------------- ### Add Extra Environment Variables Source: https://github.com/babashka/process/blob/master/README.md Use the `:extra-env` option with `process` to add environment variables without replacing the entire existing environment. Note that environment variable names are case-sensitive on Windows. ```clojure (:extra-env {"FOO" "BAR"}) ``` -------------------------------- ### Capture stdout and stderr as strings Source: https://github.com/babashka/process/blob/master/README.md Captures both standard output and standard error as strings using `:out :string` and `:err :string`. This allows for detailed inspection of command execution results. ```clojure user=> (-> (shell {:out :string :err :string} "git conpig user.name") (select-keys [:out :err])) {:out "borkdude\n", :err "WARNING: You called a Git command named 'conpig', which does not exist.\nContinuing in -1.1 seconds, assuming that you meant 'config'.\n"} ``` -------------------------------- ### Redirect Shell Output to a File Source: https://github.com/babashka/process/blob/master/README.md A simpler way to redirect the output of a `shell` command to a file. The filename is provided directly as the `:out` option. ```clojure (do (shell {:out "/tmp/out.txt"} "ls") nil) ``` -------------------------------- ### Shell-Style String Tokenization with `tokenize` Source: https://context7.com/babashka/process/llms.txt `tokenize` splits a command string into a vector of arguments, correctly handling quotes and escapes for shell-like parsing. ```clojure (require '[babashka.process :refer [tokenize]]) (tokenize "ls -la") ; => ["ls" "-la"] (tokenize "echo 'hello world'") ; => ["echo" "hello world"] (tokenize "git commit -m \"fix bug\"") ; => ["git" "commit" "-m" "fix bug"] (tokenize "a\\ b c") ; => ["a\\ b" "c"] ``` -------------------------------- ### Interpolate Clojure Values with `$` Macro Source: https://context7.com/babashka/process/llms.txt Use the `$` macro for syntactic convenience around `process`, supporting Clojure value interpolation via `~`. Options can be passed via metadata. ```clojure (require '[babashka.process :refer [$]]) (def filename "README.md") (def lines 3) ;; Interpolate Clojure values directly into the command (-> ^{:out :string} ($ head "-" ~(str lines) ~filename) deref :out println) ; => first 3 lines of README.md ;; Pass options via metadata on the form (-> ^{:out :string :dir "/tmp"} ($ ls "-la") deref :out println) ``` -------------------------------- ### Process Streaming Output Line-by-Line Source: https://context7.com/babashka/process/llms.txt For long-running streams, read `:out` line-by-line while the process runs and use `destroy-tree` to stop it. Ensure `:err` is inherited for visibility. ```clojure (require '[babashka.process :as p :refer [process destroy-tree]] '[clojure.java.io :as io]) (def counter (process {:err :inherit :shutdown destroy-tree} "bb" "-o" "-e" "(range)")) (with-open [rdr (io/reader (:out counter))] (binding [*in* rdr] (loop [n 5] (when (pos? n) (println "line:" (read-line)) (recur (dec n)))))) ; line: 0 ; line: 1 ; line: 2 ; line: 3 ; line: 4 (destroy-tree counter) ``` -------------------------------- ### Process Streaming Output Line by Line Source: https://github.com/babashka/process/blob/master/README.md Reads and prints lines from a potentially infinite stream generated by 'bb -o -e '(range)''. It uses `io/reader` to read from the process's stdout and stops after printing 10 lines. ```clojure (require '[babashka.process :as p :refer [process destroy-tree]] '[clojure.java.io :as io]) (def number-stream (process {:err :inherit :shutdown destroy-tree} "bb -o -e '(range)'")) (with-open [rdr (io/reader (:out number-stream))] (binding [*in* rdr] (loop [max 10] (when-let [line (read-line)] (println :line line) (when (pos? max) (recur (dec max))))))) ;; kill the streaming bb process: (p/destroy-tree number-stream) ``` -------------------------------- ### Add environment variables Source: https://github.com/babashka/process/blob/master/README.md Adds custom environment variables for the command execution using the `:extra-env` option. This allows passing specific configurations to the external process. ```clojure user=> (-> (shell {:out :string :extra-env {"FOO" "BAR"}} "bb -e '(System/getenv "FOO")'") :out print) "BAR" ``` -------------------------------- ### Check Process Exit Status (check) Source: https://github.com/babashka/process/blob/master/API.md The `check` function waits for a process to finish and throws an exception if its exit code is non-zero. This is useful for ensuring commands executed successfully. ```clojure (check proc) ``` -------------------------------- ### `destroy` and `destroy-tree` — Process Termination Source: https://context7.com/babashka/process/llms.txt `destroy` terminates a single process, while `destroy-tree` (JDK 9+) terminates a process and all its descendants. This is useful for cleaning up child processes. ```APIDOC ## `destroy` and `destroy-tree` — Process Termination `destroy` terminates a single process. `destroy-tree` (JDK 9+) also kills all descendant processes, falling back to `destroy` on older JVMs. ```clojure (require '[babashka.process :refer [process destroy destroy-tree alive?]]) (def p (process "sleep" "60")) (alive? p) ; => true (destroy p) (alive? p) ; => false ;; Kill entire subprocess tree on shutdown (def server (process {:shutdown destroy-tree} "node" "server.js")) ;; Immediate kill of a group of subprocesses (destroy-tree server) ``` ```