{"id":15359719,"url":"https://github.com/redhog/pieshell","last_synced_at":"2026-03-12T11:04:12.020Z","repository":{"id":54954057,"uuid":"63331689","full_name":"redhog/pieshell","owner":"redhog","description":"Python shell environment that combines the expressiveness of shell pipelines with the prower of python iterators","archived":false,"fork":false,"pushed_at":"2024-06-15T22:13:27.000Z","size":414,"stargazers_count":24,"open_issues_count":3,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-12-10T00:42:07.226Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://redhog.github.io/pieshell","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/redhog.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","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},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":"https://tinyurl.com/y5oxcwz9"}},"created_at":"2016-07-14T11:36:31.000Z","updated_at":"2024-11-02T06:03:05.000Z","dependencies_parsed_at":"2024-10-16T04:40:55.631Z","dependency_job_id":null,"html_url":"https://github.com/redhog/pieshell","commit_stats":{"total_commits":325,"total_committers":5,"mean_commits":65.0,"dds":"0.11692307692307691","last_synced_commit":"be6d59d7788f6ea5c6fa485d86b7dae0d8089155"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redhog%2Fpieshell","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redhog%2Fpieshell/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redhog%2Fpieshell/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redhog%2Fpieshell/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/redhog","download_url":"https://codeload.github.com/redhog/pieshell/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230388131,"owners_count":18217755,"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":[],"created_at":"2024-10-01T12:45:54.045Z","updated_at":"2026-03-12T11:04:11.948Z","avatar_url":"https://github.com/redhog.png","language":"Python","funding_links":["https://tinyurl.com/y5oxcwz9"],"categories":[],"sub_categories":[],"readme":"![Tests](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fredhog%2Fae708112848f5b5d4bd17e156a2f53e3%2Fraw%2F7aaf6ce62e5e8a880976d580e322e11cdd012114%2Fpieshell-junit-tests.json)\n![Test coverage](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2Fredhog%2Fae708112848f5b5d4bd17e156a2f53e3%2Fraw%2F7158c5e81be72b6387c438a9008ebcc746792558%2Fpieshell-cobertura-coverage.json)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n![PyPI - Downloads](https://img.shields.io/pypi/dd/pieshell)\n![PyPI - Downloads](https://img.shields.io/pypi/dm/pieshell)\n\n# About\n\nPieshell is a Python shell environment that combines the\nexpressiveness of shell pipelines with the power of python iterators.\n\nIt can be used in two major ways:\n\n* As an interactive shell replacing e.g. bash\n* As an ordinary python module replacing e.g. subprocess.Popen\n\n# Table of contents\n\n* [Installation](#installation)\n* [As a shell](#as-a-shell)\n  * [Executing basic commands](#executing-basic-commands)\n  * [Full syntax for command lines](#full-syntax-for-command-lines)\n  * [Redirects](#redirects)\n  * [Interfacing between python functions and shell\n    commands](#interfacing-between-python-functions-and-shell-commands)\n  * [Environment variables](#environment-variables)\n  * [Argument expansion](#argument-expansion)\n  * [Processes](#processes)\n  * [Process browsing](#process-browsing)\n  * [Job control](#job-control)\n  * [Error handling](#error-handling)\n  * [Bashsource](#bashsource)\n  * [Asynchronous IO](#asynchronous-io)\n* [As a python module](#as-a-python-module)\n  * [Environment variables](#environment-variables-1)\n  * [Argument expansion](#argument-expansion-1)\n  * [Pysh modules](#pysh-modules)\n  * [Pysh functions](#pysh-functions)\n  * [Eval and exec](#eval-and-exec)\n* [Configuration](#configuration)\n  * [Changing the prompt](#changing-the-prompt)\n* [Builtins](#builtins)\n* [External tools](#external-tools)\n* [Tips and tricks](#tips-and-tricks)\n* [Unit tests](#unit-tests)\n* [Copyright](#copyright)\n\n\n# Installation\n\n    $ pip install pieshell\n\n\n# As a shell\n\n## Executing basic commands\n\nTo start pieshell in interactive mode, just run the command pieshell:\n\n    $ pieshell\n\nThe interactive pieshell environment supports all normal python syntax.\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e print 3+4\n    7\n\nIn addition, you can run programs just like in any shell by writing\ntheir names\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e ls\n    build deps dist LICENSE.txt pieshell pieshell.egg-info README.md\n    setup.py\n\nParameters to programs however have to be given as proper python strings\nwithin parenthesis, like a python function call\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e ls(\"-a\")\n    . .. build deps dist .git .gitignore LICENSE.txt pieshell\n    pieshell.egg-info .#README.md README.md setup.py\n\nPiping the standard output of one command to the standard input of\nanother works just like in bash\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e ls(\"-a\") | grep(\"-e\", \".py\")\n    setup.py\n\nChanging directory is done using the command cd:\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e cd(\"..\")\n    140:/home/redhog/Projects/beta \u003e\u003e\u003e \n\n## Full syntax for command lines\n\nTo execute commands that require a path, for example ones in the\ncurrent directory, or commands with a dot in their names\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e _(\"./setup.py\", \"--help\")\n    Common commands: (see '--help-commands' for more)\n    ...\n\nThe underscore represents the virtual root command that has no\nparameters, not even a command name. In general, there are two\nequivalent syntaxes for parameters: as function parameter strings, and\nas attribute names. The two syntaxes can be mixed freely. All of the\nfollowing are equivalent:\n\n    _(\"foo\", \"bar\", \"fie\")\n    _.foo(\"bar\", \"fie\")\n    _.foo.bar.fie()\n    foo.bar.fie()\n    foo.bar.fie\n\nExample usage:\n\n    git.diff(\"-U\")\n\nIn addition to these two generic syntaxes, there are two more\nspecialized syntaxes for options:\n\nThe function call syntax also supports named parameters, which are\nconverted into \"--name=value\" pairs. Note that the order can not be\nguaranteed as named parameters are sent around as dictionaries inside\npython:\n\n    git.diff(unified=4)\n\nShort options, like `-U` above do not actually need quotes, and can be\nspecified inside or outside the function call syntax:\n\n    git.diff(-U, -w)\n    git.diff-U-w\n\nNotes for programs with wierd parameter syntax, like `find`: `find`\ndoes not use the standard double minus (`--`) before long options, and\ntakes the option value as a separate argument, rather than separating\nthe name and value with `=` like most programs. The above special\nsyntax for short options actually cover this use case too:\n\n    find(\".\", -name, \"*.py\")\n\n## Redirects\n\nStandard out and standard in of a pipeline can be redirected to a file\nby piping to or from a string (the filename). As a special case, None\nis a short hand for \"/dev/null\"\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e ls | \"foo\"\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e \"foo\" | cat\n    bar\n    build\n    deps\n    dist\n    foo\n    LICENSE.txt\n    pieshell\n    pieshell.egg-info\n    README.md\n    setup.py\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e ls | None\n\nRedirects can also be made with a more explicit syntax that allows\nredirecting other file descriptors than stdin and stdout:\n\n    139:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e cat |\n      Redirect(\"stdin\", \"foo\") | Redirect(\"stdout\", \"bar\")\n\nThe constructor for redirect takes the following arguments:\n\n    Redirect(fd, source, flag=None, mode=0777)\n\n`fd` can be either an int, or one of `\"stdin\"`, `\"stdout\"` and `\"stderr\"`.\n\n`source` is either a string filename, an int file descriptor or one of\nthe special values `PIPE`, `TMP` and `STRING`. `PIPE` create a new\npipe which you are required to connect up manually. `TMP` generates a\ntemporary named file. The filename is available in\n`RunningPipeline.processes[].output_files[filedescriptornr].path`.\n`STRING` generates a temporary named file, but reads and deletes it\nwhen the pipeline exists, putting its content in\n`RunningPipeline.processes[].output_content[filedescriptornr]`.\n\n`flag` and `mode` have the same semantics as for `os.open()`. Flags do\nnot have to be given for `stdin`, `stdout` and `stderr` / fd `0`, `1`\nand `2` and defaults to `os.O_RDONLY` or `os.O_RDONLY | os.O_CREAT`.\n\n## Interfacing between python functions and shell commands\n\nShell commands are first class python objects, and their input and\noutput can be interacted with easily from python in the form of\niterators. Iterating over a shell command iterates over the lines of\nits standard out\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e list(ls(\"-a\"))\n    ['.', '..', 'build', 'deps', 'dist', '.git', '.gitignore',\n     'LICENSE.txt', 'pieshell', 'pieshell.egg-info', '.#README.md',\n     'README.md', 'setup.py']\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e for x in ls(\"-a\"):\n    ...   if x.endswith('.py'):\n    ...      print x\n    ... \n    setup.py\n\nPiping an iterator into a shell command, sends its items as lines to\nthe standard in of the shell command\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e list([\"foo\", \"bar.py\", \"fie.py\"] |\n      grep(\"-e\", \".py\"))\n    ['bar.py', 'fie.py']\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e def foo():\n    ...     yield \"hello\"\n    ...     yield \"world\"\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e foo() | cat\n    hello\n    world\n\nIn addtion, iterators and pipelines may be used as arguments to\ncommands and will be seen by the command as a filename, which when\nopened and read from will produce the output of that iterator as\nlines, or the standard output of the pipeline.\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e list(cat([\"foo\", \"bar\"]))\n    ['foo', 'bar']\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e list(cat([\"foo\", \"bar\"] | cat))\n    ['foo', 'bar']\n\n## Environment variables\n\nEnvironment variables are available directly in the shell as\nvariables, together with any local python variables. In addition, they\nare available in the dictionary exports.\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e LANG\n    'en_US.UTF-8'\n\nAssigning to the name of an already exported environment variable\nupdates the value of that variable.\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e LANG = \"sv_SE.UTF-8\"\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e exports[\"LANG\"]\n    'sv_SE.UTF-8'\n\nAssigning to a variable name not already used as an environment\nvariable creates a local python variable.\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e foo = \"hello\"\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e \"foo\" in exports\n    False\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e foo\n    'hello'\n\nTo export a new variable, you have to assign it in the exports\ndictionary.\n\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e exports[\"bar\"] = \"world\"\n    140:/home/redhog/Projects/beta/pieshell \u003e\u003e\u003e bar\n    'world'\n\n## Argument expansion\n\nAll parameter strings in commands are subject to expansion unless\nwrapped in a call to R(), e.g. R(\"my * string * here\").\n\n  * \"~\" and \"~username\" are expanded using os.path.expanduser()\n\n  * Variable expansion is done using the python % operator on python\n    variables as well as environment variables.\n\n  * Pattern matching is done using glob.glob()\n\n## Processes\n\nA running pipeline is represented by a RunningPipeline instance. This\nobject is returned by the Pipeline.run() and\nPipeline.run_interactive() methods. In interactive shell mode the\nRunningPipeline instance for the last executed pipeline is available\nin the last_pipeline variable.\n\nA RunningPipeline instance can be used to extract events and statuses\nof the processes involved in the pipeline:\n\n* RunningPipeline.processes is a list of RunningItem instances, each\n  representing an external process or a python function.\n\n* RunningPipeline.failed_processes is a list of RunningItem instances\n  for those processes in the pipeline that have failed (returned a\n  non-zero exit status).\n\n* RunningPipeline.pipeline is a (deep) copy of the original pipeline\n  object, with additional run status added, e.g. links to processes,\n  exit status etc.\n\n* RunningPipeline.wait() waits for all processes in the pipeline to\n  terminate.\n\nAs a convenience, RunningItem:s can be retrieved by the name of their\ncorresponding binary as properties of the RunningPipeline. E.g.\n\n    p = ls | grep(-e, \".py\")\n    p.grep\n\nA RunningItem instance represents an external process or a python\nfunction:\n\n* RunningItem.cmd points to the part of the\n  RunningPipeline.pipeline structure that gave rise to this process.\n\n* RunningItem.is_running is True if the process is still\n  running.\n\n* RunningItem.is_failed is True if the process has failed somehow\n  (process with non-zero exit status, function threw an exception).\n\n* RunningItem.output_content contains a dictionary of the output of\n  any STRING redirection for the process with the file descriptors as\n  keys.\n\n* RunningProcess.iohandler.last_event contains a dictionary of the\n  members of the last event from the process. The members have the\n  same names and meaning as the members of the signalfd_siginfo\n  struct, see \"man signalfd\" for details.\n\n## Process browsing\n\nThis functionality is only available if `psutil` is installed.\n\nThe class `PstreeProcess` represents any process not directly started\nby Pieshell.\n\n`RunningPipeline`, `RunningItem`, and `PstreeProcess` all exposes a\nunified interface where child processes, parent processes, group\nleaders and session leaders are available as properties. Child\nporcesses uses the names of their binaries as property names. Parent\nprocesses, session and group leaders use `PARENT`, `SESS` and `GROUP`\nrespectively.\n\n`RunningItem.details`, and `PstreeProcess.details` contains a\n`psutil.Process()` instance, and most of the members and methods of\nthat instance are directly available on the `RunningItem` or\n`PstreeProcess` object.\n\nTo access a `PstreeProcess` object for the current shell and for the\ninit process (pid 1), there are two global variables `INIT` and\n`CURRENT`.\n\nThe currently logged in users and their login session processes can be\naccessed using the global `USERS` variable with a similar semantic for\nproperties.\n\nAll these objects support tab completion to let you easily naviage the\ntree of running porcesses on your system.\n\n    redhog@glittertind:~/pieshell[master] \u003e\u003e\u003e USERS.redhog.localhost.mate_panel.mate_terminal.bash.bin_bash.bash.pid_10171.python3_9\n    _('/home/redhog/pieshell/env/bin/python3.9', '/home/redhog/pieshell/env/bin/pieshell') as 26341\n    \n    redhog@glittertind:~/pieshell[master] \u003e\u003e\u003e CURRENT\n    _('/home/redhog/pieshell/env/bin/python3.9', '/home/redhog/pieshell/env/bin/pieshell') as 26341\n\n\n## Job control\n\nA pipeline can be started in the background by appending `\u0026True`, or\n`\u0026None` to do the same and also redirect stdout to /dev/null.\n\n`last_pipeline` can be used to access the backgrounded pipeline.\n\nA running pipeline can be stopped by hitting `CTRL-Z`. A stopped\npipeline can be restarted in the background with any of\n\n    bg\n    bg(last_pipeline)\n    last_pipeline.restart()\n\nor in the foreground with\n\n   fg\n   fg(last_pipeline)\n   last_pipeline.wait()\n\n## Error handling\n\nWhen a pipeline fails, e.g. by one of the involved processes exiting\nwith a non-zero status, RunningPipeline.wait() and\nPipeline.run_interactive() will throw a PipelineFailed exception after\nall processes have exited.\n\n* PipelineFailed.pipeline holds a reference to the RunningPipeline\n  instance that generated the exception.\n\nIf a pipeline is interrupted with CTRL-C, a PipelineInterrupted is\nraised.\n\n* PipelineInterrupted.pipeline holds a reference to the\n  RunningPipeline instance.\n\nIf you want to catch errors in a script, you can use normal Python\nexception handling:\n\n    try:\n    except PipelineFailed as e:\n        e.pipeline.failed_processes[0].pipeline\n\n## Bashsource\n\nBash provides the command `source` to run the content of a bash script inside the current shell,\neffectively letting an external script update the environment variables of the running shell.\nThis functionality is often used for setting up local development environments, like `virtualenv`.\n\nPieshell provides a builtin to emulate this functionality, with bash scripts:\n\n    \u003e\u003e\u003e bashsource(\"myscript.sh\")\n\nwill run `myscript.sh` in a bash shell followed by `declare -x`. It parses the output of\n`declare -x` and updates `exports` accordingly. As a special case\n\n    \u003e\u003e\u003e bashsource()\n\nwill do the same, but without running any script first, esentially\njust using whatever variables are set up by your `.bashrc` or\n`.profile`.\n\n## Asynchronous IO\n\nAll constructs described above to use iterators, can equally well be\nused as / with async iterators. Pipelines can be awaited, which runs\nthem and waits for them to exit. RunningPipelines can be awaited,\nwhich just waits for them to exit.\n\n# As a python module\n\n    \u003e\u003e\u003e from pieshell import *\n\nAll functionality available in the interactive shell is available when\nusing pieshell as an ordinary python module. However, a slighly more\ncumbersome syntax is required.\n\nIn particular, shell commands can not be run just by writing their\nnames. Instead, they have to be accessed as members of the \"env\"\nobject:\n\n    \u003e\u003e\u003e list(env.ls(\"-a\") | env.grep(\"-e\", \"io\"))\n    [\"iterio.py\", \"iterio.pyc\"]\n\nCommands are also not run with standard out to the screen when simply\nprinted using the repr() function but must instead be used as\niterators as is done above using the list() function.\n\nA pipeline can be run in the background (with input/output to the screen) using\n\n    \u003e\u003e\u003e\u003e status = ~(env.ls(\"-a\") | env.grep(\"-e\", \"io\"))\n\nor in the forground (waiting until it exists)\n\n    \u003e\u003e\u003e\u003e status = +(env.ls(\"-a\") | env.grep(\"-e\", \"io\"))\n\n\nThe env object holds the current working directory, which can be changed with\n\n    \u003e\u003e\u003e env.cd(\"..\")    \n\nYou can also create multiple environments and use them\nsiumultaneously, even within the same pipeline\n\n    \u003e\u003e\u003e env2 = env()\n    \u003e\u003e\u003e env2.cd(\"somedir\")\n\n## Environment variables\n\nEnvironment variables are available as a dictionary in env._exports.\n\n## Argument expansion\n\nVariable expansion is only done on environment variables, as there is\nno way for pieshell to find out about the right scope to do variable\nlookups in in any given situation.\n\n## Pysh modules\n\nIn addition to being able to use pieshell code in ordinary python\nmodules using this slightly more verbose syntax, pieshell supports\nimporting modules named modulename.pysh rather than modulename.py.\nPysh modules support the full syntax of the interactive pieshell\nconsole. Pysh modules can be imported using the standard import syntax\nas soon as pieshell itself has been imported, and from the interactive\npieshell.\n\nBe aware that you won't get a `NameError` for misspelled variable\nnames in pyshmodules, but instead a\n`pieshell.pipeline.running.PipelineFailed` error, or if not used in a\nway that will cause it to run, just a pipeline object stored somewhere\nit shouldn't.\n\n## Pysh functions\n\nSometimes you don't want to extract a bunch of functions to a separate\npysh module, but you'd still like to be able to use the simpler syntax\nin them. That's still possible usig the `@pyshfunction` decorator:\n\n    \u003e\u003e\u003e @pieshell.env.pyshfunction\n    \u003e\u003e\u003e def foo():\n    ...    return list(echo(\"hello\"))\n\nYou can use any environment for this, not only the default one like in\nthe example above.\n\n## Eval and exec\n\nBy giving an instance of `pieshell.environ.EnvScope` with an environment\nset to interactive as `globals` argument to either `eval` or `exec`, the\nfull syntax of Pieshell can be used in the string to evaluate/execute.\n\n    \u003e\u003e\u003e scope = pieshell.environ.EnvScope(env=pieshell.env(interactive=True))\n    \u003e\u003e\u003e eval(\"ls()\", scope)\n    build deps dist LICENSE.txt pieshell pieshell.egg-info README.md\n    setup.py\n\n# Configuration\n\nWhen running pieshell in interactive mode it executes\n`~/.config/pieshell` at startup if it exists. This file can be used to\nconfigure the interactive environment the same way `~/.bashrc` can be\nused to configure the bash shell. For example it can be used to load\npython modules, execute shell pipelines or set environment variables.\nAn example config file is supplied in\n`pieshell/resources/default_config.pysh`.\n\n## Changing the prompt\n\nThe prompt that Pieshell uses is generated by the method\n`pieshell.Environment.__str__`. This method can be overridden by\nassigning a new function to it:\n\n    def prompt(self):\n        return \"Pieshell\u003e \"\n\nBe careful if you run pipelines or other code inside the prompt that\nmight call repr() as that might lead to an infinite loop of prompt\nprinting. To solve this, use a thread local variable as a flag to\ncatch and break any recursion.\n\n# Builtins\n\nWhile pieshell lets you pipe to and from ordinary python functions,\nthey don't offer the same syntax and tab-completion as external\ncommands (e.g. 'myfunction.arg1.arg2(name=value)'), they can't modify\nthe environment or do fancy redirects. Builtin commands provide all of\nthis, at the cost of a slightly clumsier syntax:\n\n    class MyMagicBuiltin(pieshell.Builtin):\n        \"\"\"More magic to the people\n        \"\"\"\n        name = \"magic\"\n\n        def _run(self, redirects, sess, indentation = \"\"):\n            # redirects is an instance of pieshell.Redirects\n            #\n            # sess is an opaque data structure that must be passed to\n            # any call to _run() you do yourself from this method (or\n            # any function it calls).\n            #\n            # indentation is a string containing only whitespace, to\n            # be prepended to any debug printing lines you print.\n            #\n            # Returns a list of instances of some pieshell.RunningItem\n            # subclass\n\n            self._cmd = self._env.find(\n                \".\", \"-name\", \"%s.txt\" % self._arg[1]) | self._env.tac\n            return self._cmd._run(redirects, sess, indentation)\n\n\n        # Optional for tab completion\n        def __dir__(self):\n            return [\"light\", \"dark\"]\n\nBuiltins need to be registered to be available in the shell. This can\nbe done either from python with\n\n    pipeline.BuiltinRegistry.register(MyMagicBuiltin)\n\nor from setup.py in any package:\n    \n    setup(\n        entry_points={\n            'pieshell.builtin': [\n                \"magic = mypackage:MyMagicBuiltin\",\n            ]\n        }\n    )\n\n# External tools\n\nA short list of tools that might be usefull together with this project:\n\n* [psutil](http://pythonhosted.org/psutil) - python api for getting ps / top style information about a process\n* [ReRedirect](https://github.com/jerome-pouiller/reredirect) - redirect io for an already running process\n* [Reptyr](https://github.com/nelhage/reptyr) - move a running process to a new controlling terminal\n* [Deptyr](https://github.com/antifuchs/deptyr) - forward output for a new process to another controlling terminal\n\n# Tips and tricks\n\nThe [pandas reader for a table of fixed-width formatted\nlines](https://pandas.pydata.org/docs/reference/api/pandas.read_fwf.html#pandas.read_fwf)\ndoes a pretty good job at parsing the output from several standard\ncommand line tools such as ls(-l):\n\n    \u003e\u003e\u003e pd.read_fwf(io.StringIO(str(ls(-l))))\n         total 328  Unnamed: 1 Unnamed: 2 Unnamed: 3  Unnamed: 4 Unnamed: 5  Unnamed: 6 Unnamed: 7         Unnamed: 8\n    0   drwxr-xr-x           6     redhog     redhog        4096       okt.          16      21:45              build\n    1   -rw-rw-r--           1     redhog     redhog          25       jan.          11       2021        _config.yml\n    2   drwxrwxr-x           2     redhog     redhog        4096       okt.          25      21:30               dist\n    3\n\n    \u003e\u003e\u003e pd.read_fwf(io.StringIO(str(docker.images)))\n       REPOSITORY     TAG      IMAGE ID        CREATED    SIZE\n    0      python       3  a8405b7e74cf   7 months ago   921MB\n    1      ubuntu   22.04  08d22c0ceb15   7 months ago  77.8MB\n    2      ubuntu  latest  d13c942271d6  21 months ago  72.8MB\n\nThis pattern has been provided as convenience method on pipelines:\n\n    \u003e\u003e\u003e docker.images.to_dataframe()\n\nThe package libsixel-bin lets you convert images to a format that can\nbe directly displayed inside some terminal emulators. This can be\neasily combined with matplotlib to display data Jupyter Notebook\ninline style, but in your terminal:\n\n    \u003e\u003e\u003e import matplotlib.pyplot as plt, io\n    \u003e\u003e\u003e plt.scatter([1, 2, 3], [3, 2, 4])\n    \u003e\u003e\u003e buf = io.BytesIO(); plt.savefig(buf, format = 'png')\n    \u003e\u003e\u003e [buf.getvalue()] | img2sixel\n    \u003cImage displayed here in supporting terminals\u003e\n          \n# Unit tests\n\nTo run the unit- and integration tests\n\n    pip install nose2\n    nose2 -s tests\n\n# Copyright\n\nPieshell copyright 2016 Egil Möller \u003cegil.moller@piratpartiet.se\u003e\n\nPieshell is free software: you can redistribute it and/or modify it\nunder the terms of the GNU Lesser General Public License as published\nby the Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU Lesser General Public\nLicense along with this program. If not, see\n\u003chttp://www.gnu.org/licenses/\u003e.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredhog%2Fpieshell","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredhog%2Fpieshell","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredhog%2Fpieshell/lists"}