.. include:: ../../global.rst .. _`shell variables`: *************** Shell Variables *************** We need some shell variables, environment variables, etc. set up when we start. For some of these, notably, environment variables, we should be good to go as we pick up on, *duh*, the values in our environment noting there are possibly some that we *require*. We can't assume there is a :envvar:`PATH`, for example. Just out of interest let's give :program:`bash` an empty environment and then get it to print out its (created) environment: .. code-block:: console $ env - bash -c env PWD=/home/idf SHLVL=0 _=/usr/bin/env Hmm, less than I thought. Not *even* an exported :envvar:`PATH`. *Interesting.* Of course, if we print out the shell variables with ``set``, it's something more expected: .. code-block:: console $ env - bash -c set BASH=/usr/bin/bash ... IFS=$' \t\n' PATH=/usr/local/bin:/usr/bin PWD=/home/idf SHELL=/bin/bash ... Hmm, what are the semantics of process behaviour, here, with regard to environment variables? Should we intervene or be invisible? Another consideration is *how* we choose to intervene. We have a model which uses distinct *dynamic* and *environ* variables. Can we switch between the two? (Currently, no!) .. rst-class:: center \* There's also a subtlety regarding whether arguments are for us, :lname:`Idio`, or the script we are intending to run. Problems, problems! main ==== In :lname:`C`, of course, we are given ``argc`` and ``argv``. We're going to follow in the style of :lname:`Bash` and propose: .. parsed-literal:: .../idio [*Idio-args*] [*script-name* [*script-args*]] where arguments to :lname:`Idio` must come before any script name or arguments to the script as, both in essence and in practice, the first argument that isn't recognised as an :lname:`Idio` argument will be treated as the name of a script. ``--hlep`` beware! Another, slightly less obvious, issue is that there is no mechanism to load multiple libraries/scripts in one as I had been doing until "normalizing" argument handling. ``.../idio test test`` would run the test suite twice. Of course, this merely forces us to implement a :samp:`--load {name}` argument so nothing ostensibly difficult there. Except we need to be cautious about handling any errors. Variables ========= What variables, in addition to a potential :envvar:`IDIOLIB` (see :ref:`where are we`), should we be looking at creating? There's potential complications here between "shell" and environment variables and what `POSIX thinks of them `_. Here, we're don't particular feel bound by POSIX but we do want to be good neighbours. *We* might be able to handle environment variable names with "non-portable" characters in them, notably hyphens -, U+002D (HYPHEN-MINUS), but other users of the environment might not. POSIX's list of "avoid conflict with" environment variables is somewhat dubious appearing to be someone typing ``env | sort`` and dumping it in the specification. :envvar:`RANDOM` and :envvar:`SECONDS` are *environment* variables? .. rst-class:: center \* From our declaration of argument handling we should be able to derive: :var:`SHELL` (environment variable) I originally had this down as the full pathname of ``.../idio`` however POSIX thinks of it as the user's preferred command interpreter :lname:`Bash` says: expands to the full pathname to the shell. If it is not set when the shell starts, bash assigns to it the full pathname of the current user's login shell. Do as :lname:`Bash` does! :var:`IDIO_CMD` (shell variable) This is ``argv[0]`` as :lname:`Idio` sees it. It probably isn't useful but maybe someone wants to know how the command was invoked. :var:`IDIO_EXE` (shell variable) This is the kernel or ``argv[0]`` derived full pathname of the running executable. I see :lname:`Bash` has both: - :var:`_` being variously the "pathname used to invoke the shell or shell script being executed" -- before becoming other things - :var:`BASH` being "the full filename used to invoke this instance of bash" .. aside:: Not only would a variable named :var:`0` be tricky to distinguish from the number 0 but we'd start heading down the route of that old FORTRAN trick where you could swap the numbers 2 and 3, say, with hilarious results. We don't use sigils in :lname:`Idio` and we can't have a variable called :var:`0` which leaves us with :var:`ARGV0`. :var:`ARGV0` (shell variable) This is either the name of the running script or is identical to :var:`IDIO_CMD`. This is more similar to :lname:`Bash`'s :var:`$0` (and :var:`BASH_ARGV0`) which is the name of the shell script or shell if running interactively. :var:`ARGC` (shell variable) This is the number of arguments to the *script*. Clearly, if no arguments are passed to the script then :var:`ARGC` is 0. What if no script is being run, ie. we are in an interactive shell? Arguably, :var:`ARGC` should be 0 again but currently it is -1 to distinguish that case. :var:`ARGV` (shell variable) This is the arguments to the *script*. :var:`IDIOLIB` (environment variable) calculated as described above .. rst-class:: center \* Other values can be calculated and some are computed. .. note:: Most of the following are actually defined in :file:`src/libc-wrap.c` as they interact with the :lname:`C` standard library. :var:`GROUPS` (shell variable) :type: array of ``libc/gid_t`` An array of the current user's supplementary group IDs as given by :manpage:`getgroups(2)`. :var:`HOME` (environment variable) the current user's home directory :var:`HOSTNAME` (shell variable) the ``nodename`` field of a ``struct utsname`` from :manpage:`uname(3)` See also :ref:`libc/idio-uname `. .. _IDIO_PID: :var:`IDIO_PID` (shell variable) :type: ``libc/pid_t`` the result of :manpage:`getpid(2)` This value is not updated, see :ref:`PID `. .. _IFS: :var:`IFS` (dynamic variable) .. aside:: I'll probably still call it Input Field Separator, though! I've always called this the *Input* Field Separator, after :program:`awk`, but I see I am completely wrong. :program:`awk` never(?) had an :var:`IFS` but only an :var:`FS` which was "blank and tab" but separately has :var:`RS` the (input) *Record Separator* which is the newline you expect. :lname:`Bash` merged :var:`FS` and :var:`RS` into :var:`IFS` (*Internal* Field Separator) partly, I suppose, as it meant a single value would be used to split the entire multi-line output from *Command Substitution* whereas :program:`awk` would be expecting to (generally) process line by line. :program:`awk` does have distinct :var:`OFS` and :var:`ORS` when outputting whereas :lname:`Bash` uses the first character of :var:`IFS` in various expansion rules. There's no such output mangling in :lname:`Idio` -- we'd need to figure out something similar to :ref:`interpolated strings` -- so we'll hold off there. In the meanwhile, we can use the standard SPACE TAB NEWLINE for :var:`IFS`. Notice :var:`IFS` is a dynamic variable meaning you can redefine it for the duration of a block (rather than redefine it for everyone globally). .. _PID: :var:`PID` (shell variable) :type: ``libc/pid_t`` the result of :manpage:`getpid(2)` This value is updated when :lname:`Idio` forks. Compare with :ref:`IDIO_PID `. :var:`PPID` (shell variable; POSIX says environment variable) :type: ``libc/pid_t`` the result of :manpage:`getppid(2)` This value is updated when :lname:`Idio` forks. :var:`PWD` (environment variable) :type: ``libc/pid_t`` the result of :manpage:`getppid(2)` Computed Variables ------------------ :var:`UID` (shell variable) :type: ``libc/uid_t`` * accessing calls :manpage:`getuid(2)` * setting calls :manpage:`setuid(2)` :var:`EUID` (shell variable) :type: ``libc/uid_t`` * accessing calls :manpage:`geteuid(2)` * setting calls :manpage:`seteuid(2)` :var:`GID` (shell variable) :type: ``libc/gid_t`` * accessing calls :manpage:`getgid(2)` * setting calls :manpage:`setgid(2)` :var:`EGID` (shell variable) :type: ``libc/gid_t`` * accessing calls :manpage:`getegid(2)` * setting calls :manpage:`setegid(2)` :var:`SECONDS` (shell variable) :type: integer The number of seconds since the VM was started. .. note:: There is no set method for this variable. .. include:: ../../commit.rst