1 Basic Unix-style Pipelines
(require shell/pipeline) | package: shell-pipeline |
1.1 shell/pipeline stability
Unstable features are flagged in the documentation. There are a few of them, but they are mostly on functions you are not likely to use.
Forthcoming features include features such as process redirection (similar to <() and >() in Bash).
1.2 shell/pipeline guide
This library makes unix-style pipelines of external programs and racket functions easy. You can write things as simply as (run-subprocess-pipeline '(cat /etc/passwd) '(grep root) '(cut -d : -f 1)), which will print "root\n" to stdout (on unix systems) and will return a pipeline object. To get the output as a string, use run-subprocess-pipeline/out the same way. You can also put racket functions in the pipeline. If you have a racket implementation of grep called my-grep, you can do (run-subprocess-pipeline '(cat /etc/passwd) `(,my-grep root) '(cut -d : -f 1)) to get the same results. So you can write all sorts of filter functions in Racket rather than using shell commands.
Symbols in pipelines are turned into strings before they are passed in as arguments to subprocesses. Arguments to racket functions are not transformed in any way.
This library DOES work on MS Windows, and if it can’t find a program it retries the name with a .exe at the end. But Microsoft doesn’t seem to believe in having useful shell utilities, or in putting program executables on the PATH, or adding program locations to the PATH. So it will probably still be more useful on Unix than on Windows.
1.3 shell/pipeline reference
procedure
(run-subprocess-pipeline member ... [ #:in in #:out out #:err err #:strictness strictness #:lazy-timeout lazy-timeout #:background? background?]) → any/c member : (or/c list? pipeline-member-spec?)
in : (or/c input-port? false/c special-redirect?) = (current-input-port)
out :
(or/c port? false/c path-string-symbol? file-redirection-spec? special-redirect?) = (current-output-port)
err :
(or/c port? false/c path-string-symbol? file-redirection-spec? special-redirect?) = (current-error-port) strictness : (or/c 'strict 'lazy 'permissive) = 'lazy lazy-timeout : real? = 1 background? : any/c = #f
A pipeline-member-spec, in addition to the command/argument list, has an error-port specification. All lists given will be turned into pipeline-member-specs using the err specification.
Each member of the pipeline will have its current-output-port connected to the current-input-port of the next member. The first and last members use in and out, respectively, to communicate with the outside world.
All ports specified (in, out, err) may be either a port, a file-redirection-spec?, the special redirect value null-redirect , #f, or a path/string/symbol. The error port may also be stdout-redirect, in which case the output port will be used, stderr-capture-redirect, in which case the error text will be captured and added to the text of any exception, or shared-stderr-capture-redirect, which is like stderr-capture-redirect except that all parts of a pipeline that use it share the port and have their error text in the exception. If #f is given, then a port will be returned in the pipeline struct returned (similar to subprocess). If a path/string/symbol is given, then a file at that path is opened.
Beware that just as with subprocess, if you pass #f to get an input, output, or error port out of a pipeline, the resulting port may be a file-stream-port, and you will need to be sure to close it. Otherwise all file-stream-port handling in the pipeline and for file redirection is done automatically.
strictness determines how success is reported. If strictness is 'strict, then the pipeline is successful when all members are successful, and if there are errors the first member to have an error is reported. If strictness is 'lazy, success is similar, but treats any members that were killed as successful. If strictness is 'permissive, then errors are ignored except for the last pipeline member, which is what bash and most other shell languages do.
Also, if strictness is 'lazy or 'permissive, then when a pipeline member finishes, pipeline members before it may be killed. In permissive mode they may be killed immediately, and in lazy mode they have lazy-timeout seconds to finish before they are killed. This process killing happens to not wait for long (potentially infinitely so) processes in the middle of a pipeline when only a small part of their output is used. For instance, piping the output of a large file (or cat-ing an infinite pseudo-file) to the "head" command. This mirrors what bash and other shells do.
If background? is false, then run-subprocess-pipeline uses pipeline-wait to wait until it finishes, then returns the status with pipeline-status. If background? is not false, then run-subprocess-pipeline returns a pipeline object.
The default value for lazy-timeout is not stable. The semantics of the background? are not stable.
procedure
(run-subprocess-pipeline/out member ... [ #:in in #:strictness strictness #:lazy-timeout lazy-timeout]) → any/c member : (or/c list? pipeline-member-spec?)
in : (or/c input-port? false/c path-string-symbol?) = (open-input-string "") strictness : (or/c 'strict 'lazy 'permissive) = 'lazy lazy-timeout : real? = 1
lazy-timeout’s default value is not stable.
value
value
Alias for run-subprocess-pipeline.
procedure
(pipeline-member-spec? pmspec) → boolean?
pmspec : any/c
procedure
(pipeline-member-spec argl [ #:err err #:success success-pred]) → pipeline-member-spec? argl : any/c
err :
(or/c port? false/c path-string-symbol? file-redirection-spec? special-redirect?) = hidden-default-value
success-pred : (or/c false/c procedure? (listof any/c)) = hidden-default-value
err and success-pred default to values that can be overridden by the defaults set by the pipeline-running functions. But in the end they default to current-error-port and #f.
Also, pipelines are synchronizable with the sync function.
procedure
(pipeline-port-to p) → (or/c false/c output-port?)
p : pipeline?
procedure
(pipeline-port-from p) → (or/c false/c input-port?)
p : pipeline?
procedure
(pipeline-err-ports p) → (listof (or/c false/c input-port?))
p : pipeline?
procedure
(pipeline-wait p) → void?
p : pipeline?
(pipeline-wait pline) is essentially the same as (sync pline).
procedure
(pipeline-kill p) → void?
p : pipeline?
procedure
(pipeline-running? p) → boolean?
p : pipeline?
procedure
(pipeline-success? p) → any/c
p : pipeline?
procedure
(pipeline-status p) → any/c
p : pipeline?
procedure
(pipeline-status/list p) → (listof any/c)
p : pipeline?
This function is not stable.
procedure
(file-redirect file #:exists exists) → file-redirection-spec?
file : path-string-symbol? exists : (or/c 'error 'append 'truncate)
procedure
v : any/c
procedure
(special-redirect? v) → any/c
v : any/c
value
value
procedure
(shellify func) → procedure?
func : procedure?
Takes a procedure which takes a string as its first argument and returns a string. Returns a procedure which will turn its current-input-port into a string and pass it to the original procedure as its first argument. It then displays the output string of the function to its current-output-port.
This function is not stable.
This may be renamed to be less confusing with shell/pipeline-macro/define-pipeline-alias.
struct
(struct alias-func (func) #:extra-constructor-name make-alias-func) func : procedure?
If you want an alias in Rash, this is probably not what you want. See shell/pipeline-macro/define-pipeline-alias.
This will likely be renamed to be less confusing.
This is not stable.
;; A simple case -- have an alias that sets initial arguments. (define ls-alias (alias-func (λ args (list* 'ls '--color=auto args)))) ;; Slightly more complicated: `find` requires that its path argument go before ;; its modifier flags. (define find-files-alias (alias-func (λ args `(find ,@args -type f))))
procedure
(path-string-symbol? p) → boolean?
p : any/c
syntax
(and/success e ...)
syntax
(or/success e ...)
This is not stable.