Did you know ... Search Documentation:
Pack by_unix -- prolog/by_unix.pl
PublicShow source

An elegance layer to calling unix commands.

This library provides primitives that allow programmers and users to embed calls to process_create/3. The aim is to keep application code clear and succinct. This is achieved by (a) reducing the call to process_create/3 to its essential constituents and (b) allowing for term structures in the arguments of the call.

The library uses two local flags if they are defined.

    current_prolog_flag( by_unix_shell, Shell ).
    current_prolog_flag( by_unix_shell_com_arg, CmA ).

Shell should be a Unix shell such as tcsh and CmA argument should be the shell's way of saying that what ever follows is for shell to execute. When Shell is present it is used to start the commands; this allows for including user personalisations via their usual shell. When CmA is missing, -c is used (set it to '' for none at all).

On loading, the file ~/.pl/by_unix.pl will be consulted if it exists. You can add user preferences there, such as

:- set_prolog_flag( by_unix_shell, tcsh ).

The simplest example of how to use the library is:

  ?- @ ls.

This lists all files by translating ls to process_create( path(ls), [], [] ).

To list all details (long list):

        ?- @ ls(-l).

which demonstrates translation of terms in arguments.

By_unix looks at the arguments of the terms right of an @ to decide which ones are options (3rd argument of process_create/3) assuming the rest to be arguments to the call (2nd argument of process_create/3). Command arguments can be terms which will be serialised, so that a/b becomes 'a/b'. The argument * is special and it is expanded fed into expand_file_name/2.

With SWI 7 you can now have '.' in atoms, making interactions with the OS even smoother.

?- @ mkdir( -p, /tmp/test_by_unix ).
?- @ cd( /tmp/test_by_unix ).
?- @ touch( empty.pl ).
?- @ rm( -f, empty.pl ).

?- @ cd( pack(by_unix) ).
?- Wc @@ wc( -l, pack.pl ).

Wc = ['10 pack.pl'].

?- @ cd( @ '$HOME' ).
?- [Pwd] @@ pwd.
Pwd = '/home/nicos'.

?- Pass @@ bash( -c, 'read -s -p password: pass; echo $pass' ), nl.
% Sending, name: bash, args: [-c,read -s -p password: pass; echo $pass], opts:[stdout(pipe(_G1360))].
Pass = [word].

The main objective of by_unix is achieved by what has been described so far. We have found that more than 90 percent of the its uses are to produce elegant Goals that are clear to read and construct their arguments within Prolog. We provide some more features, which are described in what follows, but they should be seen as marginal.

Changing directory is not supported via cd in process_create as which cd fails to return an executable in bash. That is,

?- process_create( path(cd), ['/'], [] ).
ERROR: source_sink `path(cd)' does not exist

As oppose to:

?- [library(by_unix)].

?- @ cd( / ).

?- @ ls.
bin   dev  home        initrd.img.old  lib64	   media  opt	root  sbin     srv  tmp  var
boot  etc  initrd.img  lib	       lost+found  mnt	  proc	run   selinux  sys  usr  vmlinuz

?- @ cd( /home/nicos ).
?- @ cd( pack(by_unix) ).

which/2 provides a locator for executables. by_unix_term_to_serial/2 serialises Prolog terms to process_create/3 atoms, and by_unix_assert/0 allows for doing away with the @.

As process_create/3 quotes special characters, for instance

?- process_create( path(ls), ['*'], [] ).
/bin/ls: cannot access *: No such file or directory
ERROR: Process "/bin/ls": exit status: 2

By_unix allows for in-argument file name expansions via expand_file_name/2.

?- @ ls( -l, @('*.pl') ).

@@/2 provides dual functionality: either picking up output lines from the calling command or for maplist/2 applications. See @@/2 and @@/3.

A lines example

?- @ cd( @ '$HOME' ).
?- Pwd @@ pwd.
Pwd = ['/home/nicos'].

A maplist example

?- @ cd( pack(by_unix) ).
?- Files = ['prolog/by_unix.pl'], maplist( @@(wc(-l)), Files, Wcs ).

As of version 0.1.7 (a) failure to locate a suitable executable results to an informational message, (b) non-zero exit on the process_create/3 does no longer produce an error, but an informational message followed by failure.

?- @what(else).
% No 'what' executable could be found.

?- @ ls(who).
/bin/ls: cannot access 'who': No such file or directory
% Failed shell call: ls with args: [who].
- Nicos Angelopoulos
- 0.1.7 2014/06/09
- 0.2 2020/09/18
See also
- http://stoics.org.uk/~nicos/sware/by_unix
To be done
- error handling via message/3.
- aliases in .pl/by_unix.pl
- pick process_create options from the library declarations
- ?- Files = ['by_unix.pl'], maplist( @@ wc(-l) , Files, Wcs ). ie. fix syntax error on this
 @@(-Lines, +Comm)
@@(+Comm, -Arg)
If first argument is a variable or list, it is interpretted to be the Lines invocation, Output from Comm instantiated in Lines. Attach Arg to Comm before processing as a Unix command.
 @ +Goal
This is the main predicate of by_unix. See module documentation for examples.

For @cd( Arg ) see documentation of cd/2.

   ?- @ mkdir( -p, /tmp/test_by_unix ).
   ?- @ cd( /tmp/test_by_unix ).
   ?- @ touch( empty.pl ).
   ?- @ rm( -f, empty.pl ).
As @(Goal) but runs process in the background. This should be achivable via detached(true) option of process_create/3 but this does not seem to work on linux (tested on Mint 16). Here we use an (experimental) implementation based on threads. == ==
 which(+Which, -This)
Expand Which as a unix command in the path and return its absolute_file_name/3 in This. When Which is cd, variable This is also bound to cd. cd is handled separately as which cd fails in bash, as does process_create(path(cd), ['/'], [] ).
 by_unix_term_to_serial(Term, Serial)
Term is serialised into an atomic Serial. When Term is *, Serial is the list of current files, while when Term = @ Atom, Serial is the result of applying expand_file_name( Atom, Serial ).
 by_unix_version(-Version, -Date)
Provides version and date of current release.
 by_unix_version( 0:1:6, date(2013,12,26) ).
- nicos angelopoulos
- 0:2 2020/9/18
Retract all user:goal_expansion(_,_).
Allows for goal expansion of Com to @ Com, when Com is a which-able Unix command.
  ?- by_unix_asert.
  ?- mkdir( -p, /tmp/test_by_unix ).
  ?- cd( /tmp/test_by_unix ).
  ?- touch( empty.pl ).
  ?- ls( -l ).
  ?- rm( -f, empty.pl ).
  ?- ls( -a ).
 cd(-Old, +New)
Similar to working_directory/2, but in addition New can be a search path alias or the 1st argument of absolute_file_name/2. This is also the case when @ cd( New ) is called.
?- @ cd( pack ).

?- @ pwd.

?- @ cd( @ '$HOME' ).

?- @ pwd.

Undocumented predicates

The following predicates are exported, but not or incorrectly documented.

 @@(Arg1, Arg2, Arg3)