{"id":13761123,"url":"https://github.com/parke/lush","last_synced_at":"2025-05-10T12:30:58.425Z","repository":{"id":195421998,"uuid":"230636493","full_name":"parke/lush","owner":"parke","description":"Experimental Lua module for writing POSIX shell script style programs in Lua.","archived":false,"fork":false,"pushed_at":"2020-10-18T04:59:19.000Z","size":69,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-06T09:58:39.597Z","etag":null,"topics":["lua","shell-scripting"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/parke.png","metadata":{"files":{"readme":"readme.txt","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2019-12-28T16:47:08.000Z","updated_at":"2023-04-19T12:34:31.000Z","dependencies_parsed_at":"2023-09-17T21:59:27.629Z","dependency_job_id":null,"html_url":"https://github.com/parke/lush","commit_stats":null,"previous_names":["parke/lush"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parke%2Flush","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parke%2Flush/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parke%2Flush/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parke%2Flush/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/parke","download_url":"https://codeload.github.com/parke/lush/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253415267,"owners_count":21904822,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lua","shell-scripting"],"created_at":"2024-08-03T13:01:39.408Z","updated_at":"2025-05-10T12:30:58.109Z","avatar_url":"https://github.com/parke.png","language":"Lua","readme":"\n----  ABOUT LUSH  ----\n\nLush is a pure Lua module for writing POSIX shell script style\nprograms in Lua.  (A small number of Lush functions depend on\nluaposix.)\n\nThe primary features of Lush are:\n\n  automatic shell-style string and variable expansion\n\n  the lush.sh() function for creating and interacting with\n  subprocesses\n\n  convenience wrappers around the sh() function\n\nLush is currently experimential.  This means future versions of Lush\nmay include breaking changes.\n\n[readme.txt version 20200816]\n\n[Note:  As of October 17, 2020, I have improved and made changes to\nlush.lua.  However, I have not updated this documentation.  I believe\nthis documentation is still mostly correct, but there may be some\ninaccuracies.]\n\n\n----  STRING EXPANSION  ----\n\nSimilar to POSIX Shell, Lush supports the expansion of variables\ninside of strings.  Variables are prefixed with the dollar sign\ncharacter (\"$\").  For example:\n\nsh 'mkdir $HOME/foo'\n\nIn Lush variables are expanded lazily (when a string is used, similar\nto GNU Make).  This differs from POSIX Shell where string expansion\noccurs immediately (when a string is assigned a value).  Consider the\nfollowing Lush example:\n\nlocal  path  =  '$HOME/foo'    -- path now has the value '$HOME/foo'.\nsh 'mkdir $path'               -- The sh() function will expand '$path'\n                               --   prior to executing mkdir.\n\nIf needed, you can manually force immediate expansion as follows:\n\nlocal  path  =  expand '$HOME/foo'\n\nThere are two other supported forms of expansion:\n\necho '${HOME}/foo'      --  same as echo '$HOME/foo'\necho '${t.home}/foo'    --  where t is a table\n\nExpansion will look for each variable name in the following three\nlocations:\n\nFirst, in the local variables of the \"parent function\".\nSecond, in the _ENV of the \"parent function\".\nFinally, in the environment variables of the process.\n\nThe \"parent function\" is the function that calls sh() or expand().\n\nDuring expansion, if a name matches either a local variable or a key\nin _ENV, then the corresponding value will itself be expanded.  If a\nname matches an environment variable, then the value of that\nenvironment variable will not be expanded.  (It is assumed that\nenvironment variables are already fully expanded.)\n\nInternally, string expansion is performed via the following three\nfunctions:\n\nexpand ( v, level, ... )\nexpand_command ( o, level, ... )\nexpand_template ( s, level, ... )\n\nIn most cases, you do not need to manually call these functions as\nsh() and the other functions in Lush will handle expansion for you.\n\nlevel specfies the level on the stack where the expand functions will\nlook for local variables and for _ENV.  This is similar to the Lua\ndebug.getinfo() function.  At present, vararg parameters are not used,\nbut they may be used in a future version of Lush.\n\nlevel defaults to 1, signifying the function that called expand().\n\n'$$' expands to itself.  Therefore, expand() can be recalled\nrepeatedly on the same string without ill effect.  In other words:\nexpand ( s ) == expand ( expand ( s ) ).\n\nWhen lush.sh() executes a subprocess, '$$' will be collapsed to '$'\nimmediately prior to execution of the command.  This collapse only\nhappens once, and it happens automatically.\n\nThe value of each environment variable is assumed to be fully\nexpanded.  Consequently, when an environment variable is referenced\nduring an expansion, all '$' characters in the value of the\nenvironment variable will be replaced with '$$' to prevent\nre-expansion of an already fully expanded value.\n\nNote that an error will be raised if you tail call a function that\nexpands one or more of its arguments.  A tail call removes the parent\nfunction from the stack.  This makes it impossible for expand() to\nfind the required locals and _ENV.  (Thankfully, Lua does remember\n*that* a tail call occurred.  Therefore, expand() can at least detect\nthe a tail call occured and appropirately raise an error.  If tail\ncalls were undetectable, the tail call would silently cause an\nincorrect expansion.)\n\n\n----  FUNCTIONS  ----\n\nbasename ( path )\n\n  Expand path, then return its final directory or filename.\n\ncap ( command, ... )\n\n  A convenient way to call sh() with both\n    .capture = true and .rstrip = true.\n  In other words, expand command, run the expanded command and capture\n  its output.  Return the output as a string.  See sh() for details.\n  Example usage:  local  ls  =  cap 'ls $path'\n\ncap { command, to_list={} )\n\n  Capture the lines of stdout to the table to_list.\n  Return to_list.\n  Example usage:  local  t  =  cap { 'echo a; echo b', to_list={} }\n\ncat ( path )\n\n  Expand path, open the file at path, read the file's contents, and\n  return the contents as a string.\n\ncat { path, append=text }\n\n  Expand path, open the file at path, append text to the end of the\n  file, close the file.  Text can be a string or list of strings.\n\ncat { path, ignore=true }\n\n  Same as cat(path), except will return nil if the file does not\n  exist.\n\ncat { path, write=text }\n\n  Expand path, open the file at path, write text to the file, close\n  the file.  Text can be a string or a list of strings.\n\ncat { read_keys=path }\n\n  Expand path, open the file at path, read each line, store the lines\n  as keys in a table.  Return the table.\n\ncd ( path, trace )\n\n  chdir() to path.  If trace is true, echo 'cd  $path' before calling\n  chdir().  cd() depends on the posix.unistd module.\n\ncond ( command, ... )\n\n  A convenient way to call sh() with ignore = true.\n  Use with if to test if a program exited normally.\n  See sh() for details.\n  Example usage:  if cond '[ -f $path ]' then end\n\ncount ( n )\n\n  Use with for to loop from n to infinity.\n  Expamle usage:  for n in count (20) do end    -- will start counting at 20\n\ndirname ( path )\n\n  Return path after removing the final '/' and all characters after\n  it.\n\neach ( t [,i [,j]] )\n\n  Use with for to loop over each value in a list.\n  Example usage:  for n in each { 1, 3, 5 } do end\n\n  Optional arguments i and j can be nil, or any positive integer.\n  If i is a positive integer, each will start by   returinng t[i].\n  If j is a positive integer, each will stop after returning t[j].\n  Example usage:  for n in each ( { 1, 3, 5 }, 2, 2 ) do end\n\necho ( s )\n\n  Expand s as a template and print the expansion.  See\n  expand_template() for details.\n  (Note: In the future, echo()'s implementation may change such that\n  expansions will not be quoted.)\n\nexpand ( s )\nexpand ( s, level, ... )\n\n  Expand string s against locals and _ENV from level on the call\n  stack.  Return the expanded string.\n  level is optional and defaults to 1 (the function that called expand()).\n  The vararg ... is not used at present.\n  Example usage:  local  path  =  expand '$HOME/foo'\n\nexpand_command ( command, level, ... ).\n\n  Expand command against locals and _ENV from level on the call stack.\n  Return the expanded command as single string.\n\n  Note: Typically, you do not directly call expand_command().\n  Instead, expand_command() is called for you by sh().  However,\n  understaing expand_command() will help you reason about command\n  expansion.\n\n  Command can be a string.  If command is a string, then command is\n  expanded by expand_template().\n\n  Command can be a table (typically, a list).  If the first value in\n  the list is a string, that string is expanded by expand_template().\n  All values from the are then quoted as separate arguments.\n\nexpand_template ( info, template )\n\n  Note: Typically, you do not directly call expand_template().\n  Typically, expand_command() will call expand_teplate().  However,\n  understanding expand_template() can help you reason about command\n  expansion.\n\n  template is a string.\n\n  info is a table that contains two tables that are used during\n  variable lookup:\n     info .env     is _ENV\n     info .locals  contains the scraped local variables\n\n  expand_template() will expand the template against the variables\n  contained in info.\n\n  Template expansion is different from normal string expansion as\n  follows:\n\n  1) If a string is expanded inside a template, the string will be\n  quoted/escaped, if needed, so that the child process will receive\n  the entire string as a single argument.\n\n  2) If a table is expanded inside a template, the table will be\n  interpreted as a list.  Each elemment of the list will be expanded\n  and quoted as a separated argument.\n\n  The table can be a hierarchical tree of lists.  The tree will be\n  flattened into a list of strings.  Each string will be expanded and\n  quoted as a separate argument.\n\n  Note: You never need to quote the variables in a template.  Lush\n  quotes all templte expansions automatically, if needed.  In fact,\n  puting your own quote characters in the template is very likely to\n  cause the command to execute incorrectly, as your quotes may\n  conflict with the automatically generated quotes.\n\n  Example usage:\n  --  In actual usage, info is generated for you by the function that\n  --  calls expand_template().  For illustrative purposes only, we\n  --  manually create a stub info table here.\n  local  info  =  {\n    locals     =  { b = 'B', c = 'C C' },\n    env        =  {}  }\n  expand_template ( info, 'a $b $c' )    --  will return \"a B 'C C'\"\n\nexport ( s )\n\n  export a value to the environment.\n  s is a string of the form 'name=value'.\n  The value will be fully expanded.\n  Example usage:  export 'foo=$bar'     --  will export bar's expansion\n  Example usage:  export 'foo=$$bar'    --  will export '$bar'\n  export() depends on the posix.stdlib module.\n\ngetcwd ()\n\n  Return the current working directory.  Depends on posix.unistd.\n\nglob ( [pattern=\"*\"], flags )\n\n  Use with for and each() to iterate over paths that match pattern.\n  Exapmle usage:  for path in each ( glob '/tmp/*.txt' ) do end\n  Depends on posix.glob.\n\nhas  ( t, s )\n\n  If t is a string: has() iterates over patterns in t that match\n  '%S+'.  If one of these matches equals s, then has() returns true.\n  Otherwise, has() returns false.\n\n  If t is a table: has() returns true if s equals the value of any\n  field in t.  Otherwise, has() returns false.\n\nin_list ( k, s )\n\n  in_list() is deprecated.  Please use has() instead.\n\nimport ()\n\n  Import common Lush functions into _G.  Return a table of all Lush\n  functions (both common and uncommon).\n  Example usage:  local lush  =  require 'lush' .import()\n\nis ( s )\n\n  Access the POSIX shell's builtin test command.  This can be used,\n  for example, to determine if a file or directory exists.\n  Example usage: if is '-f $path' then end\n\npopen ( command, ... )\n\n  A convenient way to call sh() with\n    .popen = true and .iter_lines = true.\n  Use with for to iterate over the lines of output of a command.\n  See sh() for details.\n  Example usage:  for path in popen 'ls' do end\n\nprintf ( format, ... )\n\n  print ( format : format ( ... ) )\n\n  Note:  Unlike C's printf(), Lush's printf() appends a newline\n  character.  To omit the newline, use writef() instead.\n\nquote ( s )\n\n  Quote string s, allowing it to be passed to a subprocess as a single\n  command line argument to that subprocess.  You may never need to\n  call quote() directly,, as sh() automatically quotes all expansions\n  for you.\n\nsh ( command, ... )\nsh { command, [arg ... ] [\u003coption\u003e=true ... ] }\n\n  Execute command as a subprocess.\n\n  command can be a string or a list.\n\n  command will be turned into a single string by expand_command()\n\n  The expanded command will then be executed via os.execute(), or\n  when approriate, via io.popen().\n\n  At present, the vararg ... is not used.  This may change in the\n  future.  Instead of varag, you can call sh() with a table:\n    sh { command, arg1, arg2, arg3 }\n\n  If command is a table, the following six keys are optional:\n\n  If .capture == true, then sh() will capture the child process's\n    output and return it as a string.\n  If .capture == true and .rstrip == true, then remove the trailing\n    newline character from the command's output before returning the\n    command's output.\n  If .capture == true and .to_list is a table, then capture the lines\n    of stdout to to_list.  .rstrip will determine whether or not the\n    newline character is captured at the end of each line.\n  If .ignore == true, ignore the exit code of the command.\n  If .popen == true, return the result of io.popen().\n  If .popen == true and .iter_lines == true, then return an iterator\n    over the lines of command's output.\n  If .trace == true, print the command before executing it.\n\n  If command starts with the '-' character, then .ignore will be set\n  to true.  For example:  sh '-false'\n\n  Unless .ignore == true, sh() will raise an error if the command\n  exits with a non-zero exit status.\n\n  By default sh() will return the values returned by os .execute().\n  Meaning, sh() will return one of:\n    true, 'exit',   exit_status\n    nil,  'exit',   exit_status\n    nil,  'signal', signal_number\n\ntrace ( command, ... )\n\n  A convenient way to call sh() with .trace = true.\n\nwritef ( format, ... )\n\n  io .write ( format : format ( ... ) )\n\n\n----  COMPATIBILITY  ----\n\nLush is designed to work with Lua 5.3 and may also work with Lua 5.2.\nLush expects os .execute() to call a POSIX shell (that is, a shell\nthat will interpret quoted arguments in the same way that a POSIX\nshell does).\n\nAs documented above, several of Lush's functions depend on the\nluaposix module.\n\nSeveral parts of Lush would need to be modified to work with Lua 5.1.\nIn Lua 5.1, the results of os .execete() may vary by system.  This\ncould break Lush's ability to detect whether or not commands executed\nsuccessfully.  In Lua 5.1, file:close() does not return the exit\nstatus of a process that was created by io.popen.\n\nRegarding using Lush on Windwos, or on other systems with a non-POSIX\nshell, this may work if the quote function is adjusted to properly\nquote each argument.  Other unknown adjustments might also be\nrequired.\n\n\n----  FEEDBACK  ----\n\nPlease report bugs at:  https://github.com/parke/lush\nYou may contact the author at: parke.nexus at gmail.com\n","funding_links":[],"categories":["Lua"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparke%2Flush","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fparke%2Flush","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparke%2Flush/lists"}