{"id":15748331,"url":"https://github.com/binaryphile/sorta","last_synced_at":"2026-05-18T15:32:00.143Z","repository":{"id":143324983,"uuid":"91104510","full_name":"binaryphile/sorta","owner":"binaryphile","description":"Sane parameter handling in Bash, sorta","archived":false,"fork":false,"pushed_at":"2017-05-12T17:33:22.000Z","size":150,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-28T19:51:15.461Z","etag":null,"topics":["bash"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/binaryphile.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-05-12T15:22:05.000Z","updated_at":"2022-03-17T20:20:42.000Z","dependencies_parsed_at":"2023-05-14T21:15:40.493Z","dependency_job_id":null,"html_url":"https://github.com/binaryphile/sorta","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/binaryphile/sorta","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsorta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsorta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsorta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsorta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/binaryphile","download_url":"https://codeload.github.com/binaryphile/sorta/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsorta/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33182739,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-18T09:27:30.708Z","status":"ssl_error","status_checked_at":"2026-05-18T09:27:28.300Z","response_time":71,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["bash"],"created_at":"2024-10-04T05:41:23.598Z","updated_at":"2026-05-18T15:32:00.128Z","avatar_url":"https://github.com/binaryphile.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"Sane Parameter Handling in Bash, Sorta [![Build Status](https://travis-ci.org/binaryphile/sorta.svg?branch=master)](https://travis-ci.org/binaryphile/sorta)\n======================================\n\nSorta lets you write Bash functions which:\n\n-   name your function parameters\n\n-   specify the default values of parameters\n\n-   accept variable names as arguments\n\n-   expand those values into your named parameters\n\n-   accept array and hash arguments\n\n-   accept array and hash literals for those parameters\n\n-   return array and hash values\n\n-   pack/unpack variables into/out of hashes as key-value pairs\n\n-   are able to be imported a la carte via `import.bash`\n\nBasically, sorta is about controlling your variable namespace as much as\npossible. These features are designed to help you do that.\n\nThe `import.bash` library is about doing the same for your function\nnamespace. See the bottom of this document for information on its usage.\n\nRequires Bash 4.3 or higher.\n\nSo bash has an interesting way of passing variables. Since it has to\npass things to commands, which only take strings, it has to expand every\nvariable reference to a string prior to handing it to a\ncommand/function. It doesn't have a concept of passing anything other\nthan a string, even though it has structured data types such as arrays\nand hashes (a.k.a. associative arrays).\n\nSorta helps you pass arguments more like other languages do, by variable\nname.\n\nOf course this trickery has some consequences, so caveat emptor.\n\nExamples\n--------\n\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e\nWith Sorta\n\u003c/th\u003e\n\u003cth\u003e\nRegular Bash\n\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr valign=\"top\"\u003e\n\u003ctd\u003e\n\u003cpre\u003e\u003ccode\u003e\nmyvar=hello\n\nmy_function () {\n  local _params=( greeting )\n  eval \"$(passed _params \"$@\")\"\n\n  echo \"$greeting\"\n}\n\nmy_function myvar\n\n\u0026gt; hello\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cpre\u003e\u003ccode\u003e\nmyvar=hello\n\nmy_function () {\n  local greeting=$1\n\n\n  echo \"$greeting\"\n}\n\nmy_function \"$myvar\"\n\n\u0026gt; hello\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\nNotice the call to `my_function` with the name of the variable, `myvar`,\nrather than the shell expansion. `my_function`, however, doesn't see\nthat name, it just gets the already-expanded value `hello` in\n`greeting`.\n\nWith the addition of the `eval` call at the beginning of `my_function`,\nthe function receives variables by name and has them automatically\nexpanded to their values. However, you can still pass literal strings as\nwell, such as `my_function \"a string\"`. Since the value \"a string\"\ndoesn't point to a variable, it will be received, unexpanded, into\n`greeting`.\n\nThe resulting parameters are copies of the values, scoped locally to the\nfunction. Changing their values doesn't change variables in the global\nnor calling scopes, as it might if they weren't scoped locally.\n\nNotice that the `passed` function accepts the parameter array by name\n(no `\"${_params[@]}\"` expansion necessary):\n`eval \"$(passed _params \"$@\")\"`.\n\nYou could also use a literal to save a line:\n`eval \"$(passed '( greeting )' \"$@\")\"`.\n\nSo anyway, passing strings like that may be nicer than bash's syntax for\nvariable expansion, but it's not anything you can't do with bash as-is.\n\nInstead, how about passing a hash and an array directly by name:\n\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e\nWith Sorta\n\u003c/th\u003e\n\u003cth\u003e\nRegular Bash\n\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr valign=\"top\"\u003e\n\u003ctd\u003e\n\u003cpre\u003e\u003ccode\u003e\nmyarray=( zero one )\ndeclare -A myhash=( [zero]=0 [one]=1 )\n\nmy_function () {\n  local _params=( %hash @array )\n  eval \"$(passed _params \"$@\")\"\n\n\n\n\n  declare -p hash\n  declare -p array\n}\n\nmy_function myhash myarray\n\n\u0026gt; declare -A hash='([zero]=\"0\" [one]=\"1\" )'\n\u0026gt; declare -a array='([0]=\"zero\" [1]=\"one\")'\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cpre\u003e\u003ccode\u003e\nmyarray=( zero one )\ndeclare -A myhash=( [zero]=0 [one]=1 )\n\nmy_function () {\n  local hash_name=$1; shift\n  local array=( \"$@\" )\n  local -A to_hash\n\n  # since you can't pass a hash in bash\n  somehow_copy_the_hash_values_from \"$hash_name\" \"to_hash\"\n  declare -p hash\n  declare -p array\n}\n\nmy_function myhash \"${myarray[@]}\"\n\n\u0026gt; declare -A hash='([zero]=\"0\" [one]=\"1\" )'\n\u0026gt; declare -a array='([0]=\"zero\" [1]=\"one\")'\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\nYou can do this with sorta by adding special type designators to the\n`_params` list:\n\n    local _params=( %hash @array )\n\nNow your function has copies of `myhash` and `myarray` in the local\nvariables `hash` and `array`, respectively.\n\nNote that `hash` and `array` could be any variable names, I'm just using\nthose names for clarity.\n\nYour Dad's bash can't do that easily. As you can see on the right side,\nthere's no way to pass the hash. You could simply work on the hash\ndirectly in the calling scope without passing it as an argument, but\nthen your namespaces are bound together. In fact, even passing its name\nin as a reference gives the potential for naming conflicts with your\nlocal variables if you aren't careful.\n\nAdditionally, with sorta you don't have to use curly brace expansion of\nthe array, nor worry about separating other arguments from the array\nelements with `shift` at the receiving side.\n\nInstallation\n------------\n\nClone this repository and place it's `lib` directory on your path.\n\nIn your scripts you can then use `source sorta.bash` and it will be\nfound automatically.\n\n`import.bash` can also be sourced the same way since it's in the `lib`\ndirectory as well. See the bottom of this document for information on\n`import`.\n\nSorta Usage\n-----------\n\nNotably, `sorta` is not importable with `import` (see below), as it is\nsmall and coherent enough that it's not meant to be imported by parts.\n\n### Pass Scalar Values (strings and ints)\n\nTo write a function which receives variables this way, you need to\ndeclare a local array of parameter names/types, then eval the output of\nthe `passed` function:\n\n    source sorta.bash\n\n    my_function () {\n      local _params=( first second )\n      eval \"$(passed _params \"$@\")\"\n\n      echo \"first: $first\"\n      echo \"second: $second\"\n    }\n\nOutputs:\n\n    $ my_function 1 2\n    first: 1\n    second: 2\n\nSimilarly, you can call it with variable names:\n\n    $ myvar1=1\n    $ myvar2=2\n    $ my_function myvar1 myvar2\n    first: 1\n    second: 2\n\nNotice that no expansion was needed for the variable names. Of course,\nthat will still work:\n\n    $ my_function \"$myvar1\" \"$myvar2\"\n    first: 1\n    second: 2\n\nBut that's because the expansion happens prior to the function call,\nmaking this case the same as the first example which called\n`my_function` with numeric literals.\n\nYou can also index arrays and hashes when supplying scalars:\n\n    $ array=( 1 2 )\n    $ my_function array[0] array[1]\n    first: 1\n    second: 2\n\n    $ declare -A hash=( [one]=1 [two]=2 )\n    $ my_function hash[one] hash[two]\n    first: 1\n    second: 2\n\nSet Default Values\n------------------\n\nLike most high-level languages, setting a default value for a parameter\nallows you to not pass that argument into the function. In that case,\nthe parameter will be automatically set to the default value.\n\nAny default-valued parameters have to come in a contiguous set on the\nend of the definition:\n\n    source sorta.bash\n\n    my_function2 () {\n      local _params=( first=1 )\n      eval \"$(passed _params \"$@\")\"\n\n      echo \"first: $first\"\n    }\n\nOutputs:\n\n    $ my_function2 one\n    first: one\n\n    $ my_function2\n    first: 1\n\nNote that supplying an empty string overrides the default:\n\n    $ my_function2 ''\n    first:\n\nThat means calling `my_function2 \"$myvar\"`, where `myvar` is empty or\nunset, is different from calling `my_function2` without an argument.\nCaller beware.\n\nPass Arrays\n-----------\n\nArrays can be passed by name or with an array literal (see below). The\narray is passed by value, which means the receiving function gets its\nown copy of the array, not a reference to the original.\n\nTo receive an array, the entry in the parameter list is simply prefixed\nwith an \"@\" which symbolizes the expected type:\n\n    source sorta.bash\n\n    my_function3 () {\n      local _params=( @first )\n      eval \"$(passed _params \"$@\")\"\n\n      declare -p first\n    }\n\n`declare -p` shows you bash's conception of the variable, namely that\n\"first\" is an array, shown by the \"declare -a\" response:\n\n    $ array=( 1 2 )\n    $ my_function3 array\n    declare -a first='([0]=\"1\" [1]=\"2\")'\n\nTo pass a literal, use the same syntax as the right-hand side of an\nassignment statement (everything after the equals sign):\n\n    $ my_function3 '( 1 2 )'\n    declare -a first='([0]=\"1\" [1]=\"2\")'\n\nYou can use any syntax that an assignment accepts, indexed or\nnon-indexed.\n\nPass Hashes\n-----------\n\nHashes, or associative arrays, are much the same as arrays, just\nspecified with a \"%\" (thanks, Perl) rather than an \"@\":\n\n    source sorta.bash\n\n    my_function4 () {\n      local _params=( %first )\n      eval \"$(passed _params \"$@\")\"\n\n      declare -p first\n    }\n\n    $ declare -A hash=( [one]=1 [two]=2 ) # hashes require a \"declare -A\"\n    $ my_function4 hash\n    declare -A first='([one]=\"1\" [two]=\"2\" )'\n\nLiterals work much the same but require keys (unlike arrays):\n\n    $ my_function4 '( [one]=1 [two]=2 )'\n    declare -A first='([one]=\"1\" [two]=\"2\" )'\n\nBe careful to quote the values of your key-value pairs if they contain\nspaces.\n\nReturn Arrays and Hashes\n------------------------\n\nReturning scalars from functions doesn't require any special syntax\nsince you can already do this in bash:\n\n    do_something_with \"$(echo \"a string returned by echo\")\"\n\nReturning arrays and hashes isn't natively supported by bash however.\nWith sorta, you can write your functions to return a special form:\n\n    source sorta.bash\n\n    my_function5 () {\n      local array=( 1 2 )\n      pass array\n    }\n\nThe \"special form\" is just a declaration string actually. But with a\nlittle bit of help from another function, you can get it back into your\nnamespace thusly:\n\n    $ eval \"$(assign myarray \"$(my_function5)\")\"\n    $ declare -p myarray\n    declare -a myarray='([0]=\"1\" [2]=\"2\")'\n\nThat's a bit much to digest so I'll break it down:\n\n`my_function5` returns a declaration string for the array it defined:\n\n    declare -a array='([0]=\"1\" [1]=\"2\")'\n\n`assign` changes the name to \"myarray\":\n\n    declare -a myarray='([0]=\"1\" [1]=\"2\")'\n\nAnd finally, `eval` executes the declaration, putting the resulting\narray in your scope as `myarray`.\n\nNotice `my_function5` was called with the normal shell substitution\nparentheses around it to get the string it was returning.\n\nHashes are passed the same way. There's no difference in syntax for\ndealing with arrays versus hashes.\n\nImport Hash Key-Values into Local Variables\n-------------------------------------------\n\nFinally, we address importing hash values into the local namespace.\n\nNow that hashes can be passed around, it can be handy to pass a hash to\na function and then import key-value pairs from that hash into the local\nnamespace on the receiving side. `froms` imports a single key name:\n\n    source sorta.bash\n\n    my_function6 () {\n      local _params=( %myhash )\n      eval \"$(passed _params \"$@\")\"\n\n      eval \"$(froms myhash one)\"\n      echo \"one: $one\"\n    }\n\nOutputs:\n\n    $ declare -A hash=( [one]=1 )\n    $ my_function6 hash\n    one: 1\n\n`froms` can also import *all* keys from the named hash by passing `*`\nfor the name:\n\n    eval \"$(froms myhash '*')\"\n\nSince that operation can result in namespace collisions, you can make it\nsafer by applying a prefix to all of the imported names like so:\n\n    eval \"$(froms myhash 'prefix_*')\"\n\nFor example, a key named `myhash[key]` imported this way gives the\nvariable `prefix_key`.\n\nAlternatively, `froma` takes an array of key names (a literal or named\narray variable):\n\n    source sorta.bash\n\n    my_function7 () {\n      local _params=( %myhash )\n      eval \"$(passed _params \"$@\")\"\n\n      local keys=( one two three )\n      eval \"$(froma myhash keys)\"\n      echo \"one: $one\"\n      echo \"two: $two\"\n      echo \"three: $three\"\n    }\n\nOutputs:\n\n    $ declare -A hash=( [one]=1 [two]=2 [three]=3 )\n    $ my_function7 hash\n    one: 1\n    two: 2\n    three: 3\n\n`fromh` does the same as `froma` but uses a hash mapping to specify the\nnames of the variables to import the keys to:\n\n    source sorta.bash\n\n    my_function8 () {\n      local _params=( %myhash )\n      eval \"$(passed _params \"$@\")\"\n\n      local -A keymap=( [one]=singing [two]=inthe [three]=rain )\n      eval \"$(fromh myhash keymap)\"\n      echo \"singing: $singing\"\n      echo \"inthe: $inthe\"\n      echo \"rain: $rain\"\n    }\n\nOutputs:\n\n    $ declare -A hash=( [one]=1 [two]=2 [three]=3 )\n    $ my_function8 hash\n    singing: 1\n    inthe: 2\n    rain: 3\n\nFAQ\n---\n\n-   *Why?*\n\n    The command line is the fundamental tool for system management, and\n    bash is its de facto interface. For many such uses, it's the lowest\n    impedance tool for the job, beating out other scripting tools by\n    virtue of staying out of your way. Bash has the added virtue of\n    being preinstalled on almost every major Unix distribution.\n\n    When trying to do anything somewhat sophisticated however, bash\n    quickly falls on its face due to its weak support for passing\n    parameters, its use of [dynamic scoping] and its lack of support for\n    reasonable packaging of libraries.\n\n    Sorta is aimed at improving parameter passing just a bit, so you can\n    more effectively use the tools which bash does provide.\n\n-   *Why \"\\_params\"?*\n\n    In order for the `passed` function to determine whether an argument\n    needs to be expanded, it has to check the outside scope for the\n    existence of variable names. If it finds one, it reads in\n    that value. Therefore you don't want to declare any local variables\n    before calling `passed`, since those might mask an outside variable\n    name that was passed as an argument.\n\n    If the parameter list is declared as a variable (as opposed to a\n    literal), then it may also mask an argument. Prefixing it with an\n    underscore prevents most possibilities for a name collision.\n\n-   *What if I want to pass a string that happens to be a variable name\n    as well? Won't it be expanded when I don't want it to be?*\n\n    Short answer, yes, the string will be expanded if `passed` detects\n    that it is a reference to a variable name. If you don't want it\n    expanded, there are two things you can do (other than not use\n    `passed`):\n\n    -   Make the parameter an array instead and pass the argument as an\n        entry in the array. Array items are not expanded.\n\n    -   Make the parameter a reference type, by qualifying it with a\n        \"\\*\" in the parameter list. If the variable name held by the\n        argument is not itself a reference, no expansion will be done.\n        Since this is less reliable, option (1) is recommended instead.\n\n-   *Should I use sorta's `passed` function to pass user input to\n    functions?*\n\n    As scalars, no, you generally shouldn't use `passed` for any data\n    which might inadvertently contain just a variable name, which would\n    get expanded when you wouldn't want it to.\n\n    However you *can* pass such data through arrays, which are not\n    expanded, as described above.\n\n-   *What about the positional arguments, $1, $2, etc.?*\n\n    The positional arguments are left intact and may be used in addition\n    to the arguments created by `passed`. You may even use them to tell\n    when an expansion has occurred, which is occasionally useful.\n\nSorta API\n---------\n\n\"Accepts literals or variable names\" means that the arguments may be\nspecified normally, using string literals or expansions for example, or\nwith the bare name of a variable (as a normal string argument). If the\nreceiving function detects that the supplied argument is the name of a\ndefined variable, it will automatically expand the variable itself.\n\nArray and hash (associative array) literals may also be passed as\nstrings for parameters expecting those types. Any literal that would\nwork for the right-hand-side of an assignment statement works in that\ncase, such as `'( [one]=1 [two]=2 )'` (remember to use single- or\ndouble-quotes).\n\n-   **`assign`** *`variable_name declaration_statement`* - change the\n    variable name of a declaration statement to `variable_name`\n\n    *Returns*: the substituted declaration statement on stdout\n\n    Allows you to assign the output of `pass` to a variable name in the\n    local scope. You must `eval` the output of `assign` to do so.\n\n-   **`assigna`** *`variable_name_array declaration_statement`* - change\n    the names in a compound declaration statement\n\n    *Returns*: the substituted declarations on stdout\n\n    Allows you to reassign the names of a compound series of declaration\n    statements to the names in the array. A compound declaration is a\n    series of individual declaration statements, usually separated with\n    semicolons, joined into a single string. It is up to you to ensure\n    that the number of names and available statements match. You must\n    `eval` the output of `assigna` to instantiate the variables locally.\n\n-   **`froma`** *`hash keys`* - create declaration statements for a set\n    of variables named in the array `keys`, values taken from the named\n    hash\n\n    Accepts literals or variable names.\n\n    *Returns*: a compound declaration statement on stdout\n\n    For the named hash, returns a set of declaration statements, joined\n    by semicolons, for variables named in `keys`. The values are taken\n    from the corresponding keys of `hash`.\n\n    You must `eval` the output of `froma` to instantiate the\n    variables locally.\n\n-   **`fromh`** *`hash keyhash`* - create declaration statements for a\n    set of variables named in the keys of `keyhash`, values taken from\n    `hash`\n\n    Accepts literals or variable names.\n\n    *Returns*: a compound declaration statement on stdout\n\n    For the named hash, returns a set of declaration statements, joined\n    by semicolons, for the keys of `hash` corresponding to the keys of\n    `keyhash`, mapped to variables named by the values of `keyhash`.\n\n    You must `eval` the output of `froma` to instantiate the\n    variables locally.\n\n-   **`froms`** *`hash name_or_pattern`* - create\n    declaration statement(s) for named variable or set of variables,\n    values taken from from `hash`\n\n    Accepts literals or variable names.\n\n    *Returns*: a declaration statement or compound declaration statement\n    on stdout\n\n    When supplied with a single name, creates a declaration statement\n    for the named variable with the value taken from the corresponding\n    key in `hash`.\n\n    When supplied with the pattern '\\*' (include quotes to prevent\n    globbing), creates a compound declaration statement for variables\n    with *all* of the keys and values of `hash`.\n\n    When supplied with a prefixed asterisk, such as 'myvars\\_\\*',\n    creates a compound declaration as above but with the prefix on the\n    resulting variable names.\n\n    You must `eval` the output of `froms` to instantiate the\n    variable(s) locally.\n\n-   **`intoa`** *`hash keys [return_variable]`* - return a hash which\n    includes the variables named in `keys` as new keys\n\n    Accepts literals or variable names.\n\n    *Returns*: a declaration statement on stdout, or a hash in\n    `return_variable`, if supplied\n\n    Adds the variables named in `keys`, and their values, to the\n    named hash.\n\n    Existing keys of the same name are overwritten. Other key-values in\n    the hash are left alone. This is basically a merge operation.\n\n    `return_variable`, if supplied, must be a hash variable declared\n    outside the scope of `intoa`, and may be the same as the named hash.\n\n    Otherwise you must `eval` the output of `intoa` to update the hash\n    with the new values.\n\n-   **`intoh`** *`hash keyhash [return_variable]`* - return a hash which\n    includes the variables named in `keyhash` as new keys\n\n    Accepts literals or variable names.\n\n    *Returns*: a declaration statement on stdout, or a hash in\n    `return_variable`, if supplied\n\n    Adds the variables named in `keyhash`, and their values, to the\n    named hash. `keyhash` is a mapping of the variables names to the\n    keynames under which their values will be inserted into `hash`.\n\n    Existing keys of the same name are overwritten. Other key-values in\n    the hash are left alone. This is basically a merge operation.\n\n    `return_variable`, if supplied, must be a hash variable declared\n    outside the scope of `intoh`.\n\n    Otherwise you must `eval` the output of `intoh` to update the hash\n    with the new values.\n\n-   **`intos`** *`hash key [return_variable]`* - return a hash which\n    includes the variable named in `key`\n\n    Accepts literals or variable names.\n\n    *Returns*: a declaration statement on stdout, or a hash in\n    `return_variable`, if supplied\n\n    Adds the variable named by `key`, and its value, to the named hash.\n\n    An existing key of the same name is overwritten. Other key-values in\n    the hash are left alone. This is basically a merge operation.\n\n    `return_variable`, if supplied, must be a hash variable declared\n    outside the scope of `intos`, and may be the same as the named hash.\n\n    Otherwisee you must `eval` the output of `intos` to update the hash\n    with the new values.\n\n-   **`keys_of`** *`hash [return_variable]`* - return an array of the\n    key names from `hash`\n\n    Accepts a literal or variable name.\n\n    *Returns*: a declaration statement on stdout or the value in\n    `return_variable`, if supplied\n\n    `return_variable`, if supplied, must be an array variable declared\n    outside the scope of `values_of`.\n\n    Finds and returns an `eval`able array of the key names from the\n    named `hash`.\n\n-   **`pass`** *`variable_name`* - create a declaration statement for an\n    the named variable\n\n    *Returns*: a declaration statement on stdout\n\n    Returns an `eval`able statement to instantiate the given variable in\n    a scope, usually as a return value from a function.\n\n    Equivalent to `declare -p \u003cvariable_name\u003e 2\u003e/dev/null`.\n\n-   **`passed`** *`parameter_array arg1 [arg2...]`* - create a compound\n    declaration statement for the named variable parameters with the\n    supplied argument values\n\n    Accepts literals or variable names.\n\n    *Returns*: a declaration statement on stdout\n\n    Reserves for internal use any variable names starting with double\n    underscores, so such names are not allowed in parameter lists.\n    `passed` does not support such parameter names.\n\n    Returns an `eval`able statement to instantiate the given variables\n    in a scope, usually as the first task in your function.\n\n    Named parameters are presumed to be scalars unless prefixed with the\n    following qualifiers:\n\n    -   `@` - argument is an array name or literal\n\n    -   `%` - argument is a hash name or literal\n\n    -   `\u0026` - parameter is aliased to the variable name given by\n        argument with `declare -n`\n\n    -   `*` - argument is a reference to another variable name\n\n    Note that `\u0026` and `*` require the quoting since bash treats them as\n    special characters.\n\n    Scalar arguments are tested to see if they refer to variables. If\n    so, they are dereferenced so the resulting declaration holds the\n    value of the referenced variable.\n\n    Array and hash parameters are presumed to hold references to an\n    array or hash in the outer scope, or to hold an array/hash literal.\n    A literal, in this case, is any string which qualifies as the\n    right-hand side of an assignment statement, i.e. that which follows\n    the equals sign. See the format of any `declare -p` output\n    for examples.\n\n    The `*` reference type tells `passed` to expect the result to be a\n    variable name. It still dereferences an argument if the dereferenced\n    argument's value is the name of another variable, but will prevent\n    dereferencing if the argument is simply a variable reference and\n    nothing more.\n\n    The `\u0026` dereference type sets the parameter to point to the variable\n    named by the argument directly, effectively making it call\n    by reference. Changes to the parameter variable in the function body\n    will affect the original variable directly in the outer scope. This\n    is not call by value.\n\n    All parameters in the list may have a default value specified by\n    appending `=\u003cvalue\u003e` to the parameter name. Parameters with default\n    values must, however, be contiguous at the end of the list.\n\n    You must `eval` the output of `passed` to instantiate the variables.\n\n-   **`ret`** *`return_variable string_value|array_name|hash_name`* -\n    return a value via a named return variable\n\n    *Returns*: the value, in `return_variable`\n\n    `return_variable` must exist outside of your function scope, usually\n    declared by your function's caller. The existing variable must also\n    be the appropriate type; scalar, array or hash (a.k.a.\n    associative array).\n\n    `return_variable` is therefore usually passed into your function as\n    an argument, which is then passed onto `ret`.\n\n    Example:\n\n          myfunc () {\n            return_variable=$1\n\n            local \"$return_variable\" || return\n            ret \"$return_variable\" 'my value' # pass back a string\n          }\n\n    Before calling `ret`, your function must also declare\n    `return_variable` locally, as shown. Since the variable name may not\n    be a valid identifier string, this is usually done with a `return`\n    clause in case it errors. This should only be done right before\n    calling `ret`.\n\n    You could accomplish the same thing without `ret` by using\n    indirection via `local -n ref` or `${!ref}`, but both of these allow\n    the referenced variable name to conflict with your local variables.\n    `ret` prevents naming conflicts with your local variables.\n\n    Calling `ret`, however, does unset the named variable in your\n    function's scope. If the variable name is also used by one of your\n    local variables (always possible), then your variable will be unset.\n    Therefore you may not be able to rely on variables after calling\n    `ret`, so you should only do so right before your function returns.\n\n    The returned value(s) may be a scalar value, or may be contained in\n    a named array or hash. If passing an array or hash, simply use the\n    variable name as the second argument. If passing back a scalar\n    value, use the value, not its variable name (if stored in\n    a variable).\n\n    As a corollary, the `ret` function is unable to pass back the names\n    of arrays or hashes as scalar values. They will always be passed as\n    their array values. Be forewarned.\n\n    `ret` is based on the discussion \\[here\\], but is enhanced to pass\n    arrays by name.\n\n    It is also a wrapper for the `_ret` function from \\[nano\\], which is\n    the actual implementation.\n\n-   **`values_of`** *`hash [return_variable]`* - return an array of the\n    values (corresponding to keys) from `hash`\n\n    Accepts a literal or variable name.\n\n    *Returns*: a declaration statement on stdout, or the value in\n    `return_variable`, if supplied\n\n    `return_variable`, if supplied, must be an array variable declared\n    outside the scope of `values_of`.\n\n    Finds and returns an `eval`able array of the values from the named\n    `hash`.\n\nimport.bash\n===========\n\n`import.bash` is another library included with sorta. It allows you to\nwrite libraries that may have their functions imported a la carte.\n\nFor example, if you have a library named `my_great_library.bash` which\nhas been written with `import` in mind, you can get functions from it\nlike so:\n\n    source import.bash\n\n    mgl_imports=(\n      my_great_function1\n      my_great_function2\n    )\n    eval \"$(importa my_great_library mgl_imports)\"\n\nIf `my_great_library.bash` has 100 functions defined, you will only get\nthe two you wanted, plus dependencies.\n\nAny functions which are dependencies of `my_great_library` will be\nimported as well, but that is handled automatically at import time by\nsome meta-information you add to your library.\n\nThere are two primary benefits provided by `import.bash`:\n\n-   it gives you control over the function namespace when sourcing\n    libraries, making it easier to effectively structure your code into\n    libraries or use others' code\n\n-   it provides you a trail back to the source file of functions used in\n    your code. By tying the function name to the source file when the\n    function is imported, you are able to explicitly see where the\n    function came from. This makes it easier to use multiple libraries\n    in your code since you can tell from where functions originated when\n    you need to examine their implementations.\n\n`import.bash` works by opening a subshell, importing the named library,\nand then extracting and `eval`ing the code for the functions you care\nabout. Performance may be an issue with large files, since you are\nparsing potentially a large amount of code twice rather than once.\n\nImport Usage\n------------\n\nThe basic usage pattern for the consumer of an import-compatible library\nis above. The `imports` function imports an individual function (the \"s\"\nis for string), while the `importa` function imports an array of\nfunction names.\n\nThe library name may be qualified with its file extension (e.g. `.sh`),\nbut if it is not qualified, it will be searched for without an\nextension, then with \".bash\" and \".sh\" extensions.\n\nWriting libraries which can be imported is the other half of the\npicture. The only requirement is that any dependencies of the library's\nfunctions are listed in a special variable, `_required_imports`,\ndeclared by the library.\n\nFor example, if you have a function `one` which calls function `two`,\nyour library would look like so:\n\n    _required_imports=(\n      two\n    )\n\n    one () {\n      echo \"Calling 'two'...\"\n      two\n    }\n\n    two () {\n      echo \"Hello from 'two'.\"\n    }\n\nNote that you do not need to source `import.bash`.\n\nThe reason is that the `import` functions do not do any dependency\nanalysis of their own. Although `one` calls `two` and depends on it to\nsucceed, importing `one` won't automatically import `two` if you don't\nimport `two` explicitly as well. Because of that, calling `one` will\nfail when it tries to use `two`, unless you include it in your\n`_required_imports`.\n\nThe same goes for dependencies satisfied by libraries sourced by your\nlibrary. To make it possible for any function in your library to be\nimported, you will have to determine all of the functions called by any\nof your library's, wherever they have been defined, and list their names\nin `_required_imports` in your library. For example, if `two` had been\ndefined in a separated file, it still would have needed to be listed in\n`_required_imports` in the file where `one` is defined.\n\nAnything in `_required_imports` will automatically be imported so the\nconsumer of your library won't have to handle that dependency analysis.\n\nThis means that if you have a lot of dependencies, you will be getting\nsome extra baggage with your imports, so be aware that just because you\nnamed one function to import, it doesn't mean you won't get others as\nwell in the bargain. Still, you're usually keeping your namespace\ncleaner than it would have been if you had imported the entirety of a\nlibrary that only had a handful of functions in which you were actually\ninterested.\n\n  [dynamic scoping]: https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scoping_vs._dynamic_scoping\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinaryphile%2Fsorta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbinaryphile%2Fsorta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinaryphile%2Fsorta/lists"}