{ "info": { "author": "Timoth\u00e9e Mazzucotelli", "author_email": "pawamoy@pm.me", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7" ], "description": "# Shell History\n[![pipeline status](https://gitlab.com/pawamoy/shell-history/badges/master/pipeline.svg)](https://gitlab.com/pawamoy/shell-history/commits/master)\n\nInspired by [bamos/zsh-history-analysis](https://github.com/bamos/zsh-history-analysis).\n\nVisualize your usage of Bash/Zsh through a web app\nthanks to [Flask](http://flask.pocoo.org/) and [Highcharts](https://www.highcharts.com/)!\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Duration\"durationLength\"lengthType\"type
Exit code\"exitHourly\"hourlyDaily\"daily
Over time\"overMarkov chain\"markovTop commands\"top
\n\n

Post your charts ideas in this issue!

\n\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Setup](#setup)\n- [Usage](#usage)\n- [Some technical info](#some-technical-info)\n - [How it works](#how-it-works)\n - [History file format](#history-file-format)\n - [How we get the values](#how-we-get-the-values)\n- [License](#license)\n\n## Requirements\n`shellhistory` requires Python 3.6 or above.\n\n
\nTo install Python 3.6, I recommend using pyenv.\n\n```bash\n# install pyenv\ngit clone https://github.com/pyenv/pyenv ~/.pyenv\n\n# setup pyenv (you should also put these two lines in .bashrc or similar)\nexport PATH=\"${HOME}/.pyenv/bin:${PATH}\"\neval \"$(pyenv init -)\"\n\n# install Python 3.6\npyenv install 3.6.7\n\n# make it available globally\npyenv global system 3.6.7\n```\n
\n\n## Installation\nWith `pip`:\n```bash\npython3.6 -m pip install shellhistory\n```\n\nWith [`pipx`](https://github.com/pipxproject/pipx):\n```bash\npython3 -m pip install --user pipx\n\npipx install --python python3.6 shellhistory\n```\n\n## Setup\n`shellhistory` needs a lot of info to be able to display various charts.\nThe basic shell history is not enough. In order to generate the necessary\ninformation, you have to enable the shell extension.\n\nAt shell startup, in `.bashrc` or `.zshrc`, put the following:\n\n```bash\n# only load it for interactive shells\nif [[ $- == *i* ]] && command -v shellhistory-location &>/dev/null; then\n . $(shellhistory-location)\n shellhistory enable\nfi\n```\n\n... and now use your shell normally!\n\nIf you want to stop `shellhistory`, simply run `shellhistory disable`.\n\n**Note:** *for performance reasons, you can also use the static,\nabsolute path to the source file.\nIndeed, calling `shellhistory-location` spawns a Python process\nwhich can slow down your shell startup.\nGet the path once with `shellhistory-location`, and use `. `.\nIn my case it's `. ~/.local/pipx/venvs/shellhistory/lib/python3.6/site-packages/shellhistory/shellhistory.sh`.*\n\n## Usage\nLaunch the web app with `shellhistory-web`.\nNow go to [http://localhost:5000/](http://localhost:5000/) and enjoy!\n\nYou will need Internet connection since assets are not bundled.\n\n## Some technical info\n### How it works\nWhen you enter a command, `shellhistory` will compute values\n*before* and *after* the command execution.\nIn Bash, it uses a trap on DEBUG and the PROMPT_COMMAND variable\n(`man bash` for more information).\nFor Zsh, it uses the preexec_functions and precmd_functions arrays\n(anyone knows where to find the official documentation for these?\nSome information in `man zshmisc`).\n\nBefore the command is executed, we start a timer, compute the command type,\nand store the current working directory and the command itself.\n\nAfter the command has finished, we store the return code, and stop the timer.\n\n### History file format\nFields saved along commands are start and stop timestamps, hostname, username,\nuuid (generated), tty, process' parents, shell, shell level, command type,\nreturn code, and working directory (path), in the following format:\n`:start:stop:uuid:parents:host:user:tty:path:shell:level:type:code:command`.\n\n- multi-line commands are prepended with a semi-colon `;` instead of a colon `:`,\n starting at second line\n- start and stop timestamps are in microseconds since epoch\n- process' parents and working directory are encoded in base64 to avoid\n delimiter corruption.\n\nExample (multi-line command):\n\n```\n:1510588139930150:1510588139936608:40701d9b-1807-4a3e-994b-dde68692aa14:L2Jpbi9iYXNoCi91c3IvYmluL3B5dGhvbiAvdXNyL2Jpbi94LXRlcm1pbmFsLWVtdWxhdG9yCi91c3IvYmluL29wZW5ib3ggLS1zdGFydHVwIC91c3IvbGliL3g4Nl82NC1saW51eC1nbnUvb3BlbmJveC1hdXRvc3RhcnQgT1BFTkJPWApsaWdodGRtIC0tc2Vzc2lvbi1jaGlsZCAxMiAyMQovdXNyL3NiaW4vbGlnaHRkbQovc2Jpbi9pbml0Cg==:myhost:pawamoy:/dev/pts/1:L21lZGlhL3Bhd2Ftb3kvRGF0YS9naXQvc2hlbGxoaXN0Cg==:/bin/bash:1:builtin:0:echo \"a\n;b\n;c\" | wc -c\n```\n\n**Note:** later we could use CSV formatting, quoting\nstrings and doubling double-quotes in those if any.\nIt would make the file more readable for humans,\nand easily importable in other programs.\nSee [issue 26](https://github.com/pawamoy/shell-history/issues/26).\n\nThe previous example would look like this:\n```\n1510588139930150,1510588139936608,40701d9b-1807-4a3e-994b-dde68692aa14,\"/bin/bash\n/usr/bin/python /usr/bin/x-terminal-emulator\n/usr/bin/openbox --startup /usr/lib/x86_64-linux-gnu/openbox-autostart OPENBOX\nlightdm --session-child 12 21\n/usr/sbin/lightdm\n/sbin/init\",myhost,pawamoy,/dev/pts/1,\"/media/pawamoy/Data/git/shellhist\",/bin/bash,1,builtin,0,\"echo \"\"a\nb\nc\"\" | wc -c\"\n```\n\n### How we get the values\nStart and stop time are obtained with `date '+%s%N'`, return code is passed\ndirectly with `$?`, working directory is obtained with `$PWD` and command\ntype with `type` for Bash and `whence` for Zsh.\n\nValues for UUID, parents, hostname, and TTY are computed only once, when\n`shellhistory.sh` is sourced. Indeed they do not change during usage of the current\nshell process. Hostname and TTY are obtained through commands `hostname` and\n`tty`. UUID is generated with command `uuidgen`. Also note that UUID\nis exported in subshells so we know which shell is a subprocess of another, and\nso we are able to group shell processes by \"sessions\", a session being an opened\nterminal (be it a tab, window, pane or else). Parents are obtained with a\nfunction that iteratively greps `ps` result with PIDs (see `shellhistory.sh`).\n\nValues for user, shell, and level are simply obtained through environment\nvariables: `$USER`, `$SHELL` (though its use here is incorrect:\nsee [issue 24](https://github.com/pawamoy/shell-history/issues/24)),\nand `$SHLVL` (also see [issue 25](https://github.com/pawamoy/shell-history/issues/25)).\n\nThe last command is obtained with the command `fc`.\nUsing `fc` allows `shellhistory` to have the same behavior as your history:\n- if commands starting with spaces are ignored, they will be ignored\n in `shellhistory` as well.\n- same for duplicates (entering `ls` two or more times\n saves only the first instance). Note however that if you type the same command\n as the previous one in an other terminal, it will still be appended,\n unless you manage to synchronize your history between terminals,\n which is another story.\n\nAdditionally, if you enter an empty line,\nor hit Control-C before enter, nothing will be appended either.\nThe trick behind this is to check the command number in the current history\n(see `shellhistory.sh` for technical details).\n\n## License\nSoftware licensed under the\n[ISC](https://www.isc.org/downloads/software-support-policy/isc-license/)\nlicense. See the [LICENSE](/LICENSE) file.\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/pawamoy/shell-history", "keywords": "shell,bash,zsh,history,analysis,visualization", "license": "ISC", "maintainer": "Timoth\u00e9e Mazzucotelli", "maintainer_email": "pawamoy@pm.me", "name": "shellhistory", "package_url": "https://pypi.org/project/shellhistory/", "platform": "", "project_url": "https://pypi.org/project/shellhistory/", "project_urls": { "Homepage": "https://github.com/pawamoy/shell-history", "Repository": "https://github.com/pawamoy/shell-history" }, "release_url": "https://pypi.org/project/shellhistory/0.2.4/", "requires_dist": [ "flask (>=1.0,<2.0)", "Flask-Admin (>=1.5,<2.0)", "sqlalchemy (>=1.3,<2.0)", "tqdm (>=4.28,<5.0)" ], "requires_python": ">=3.6,<4.0", "summary": " Visualize your shell usage with Highcharts!", "version": "0.2.4" }, "last_serial": 5282351, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "8c3c706d07960a3d27e5087fe717a337", "sha256": "448f90d15378c32732bc05412aa940925c11c624b04bee376c3efefb501115eb" }, "downloads": -1, "filename": "shellhistory-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "8c3c706d07960a3d27e5087fe717a337", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<3.7", "size": 60833, "upload_time": "2018-12-23T15:59:20", "url": "https://files.pythonhosted.org/packages/dd/b8/f3ba62d6c7ad6fa2ba99225190986020bc87ecfc0ff2cf945952b7c208a9/shellhistory-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7c5b11dfa205bfb97908288a358cdc18", "sha256": "371415bba6df7adff6c36d8c3a9184ba2280337248f276d52417a9698a8d2be8" }, "downloads": -1, "filename": "shellhistory-0.1.0.tar.gz", "has_sig": false, "md5_digest": "7c5b11dfa205bfb97908288a358cdc18", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<3.7", "size": 17915, "upload_time": "2018-12-23T15:59:22", "url": "https://files.pythonhosted.org/packages/47/93/b9221a90056014086bf5e5458bc9ef83a79d9d82e49c1d39b796be9bf890/shellhistory-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "be480341b9d7890ed48f1046a46a8506", "sha256": "25da79cfca17074dd62bf380b3d82faa36af0c6c5b8c22c06da3a4262b759679" }, "downloads": -1, "filename": "shellhistory-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "be480341b9d7890ed48f1046a46a8506", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<3.7", "size": 60964, "upload_time": "2018-12-23T16:17:04", "url": "https://files.pythonhosted.org/packages/16/f5/404ec0e95ee0634ebc1767537276cc0f3b35fb159cafd7bc9039470200c5/shellhistory-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4f9e620274c41c0f4de907f9a02ae9eb", "sha256": "d6ad0a7441f42e1d98f96ceb157b6b55e2288f30275e6b914c14922e1444612b" }, "downloads": -1, "filename": "shellhistory-0.1.1.tar.gz", "has_sig": false, "md5_digest": "4f9e620274c41c0f4de907f9a02ae9eb", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<3.7", "size": 17961, "upload_time": "2018-12-23T16:17:05", "url": "https://files.pythonhosted.org/packages/5e/12/cb4602ebf7632f25689673334e131fc0122d40be649df4dba6ef0f04ffc3/shellhistory-0.1.1.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "14799f2807a63e91afc81c04e38b3b57", "sha256": "3b3b80bcb24f7492f8a179d577ff6837662bc8cde6138131b8e20a16443c76fb" }, "downloads": -1, "filename": "shellhistory-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "14799f2807a63e91afc81c04e38b3b57", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<3.7", "size": 62415, "upload_time": "2018-12-23T21:47:21", "url": "https://files.pythonhosted.org/packages/5c/20/eb319e517e574d52f6f8af01e44b36dd7860345c96f015656ca4d3765d03/shellhistory-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "bc96bd6a4703da9f82b74734266a22fa", "sha256": "2e55e764cf016ffe6fc02707b9edcfb20d95401668d6332a32e9a3f54b02b549" }, "downloads": -1, "filename": "shellhistory-0.2.0.tar.gz", "has_sig": false, "md5_digest": "bc96bd6a4703da9f82b74734266a22fa", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<3.7", "size": 18538, "upload_time": "2018-12-23T21:47:23", "url": "https://files.pythonhosted.org/packages/b6/86/d0f22389c62ddf1feafab4810b546154702309ca72f1cb5be0e382c87482/shellhistory-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "a8fee8a467aeb4f90d3316ae89d987ed", "sha256": "61fb27f8b472402a08b494953a57c1874c267a5a2e321e9adf20a8d2c5d939ab" }, "downloads": -1, "filename": "shellhistory-0.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "a8fee8a467aeb4f90d3316ae89d987ed", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<3.7", "size": 73898, "upload_time": "2018-12-26T16:45:16", "url": "https://files.pythonhosted.org/packages/c9/ca/1681ebd2e4ba9718f5e411751f06f4f1939972879877c7b2517da511428c/shellhistory-0.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f679809b7fd17fe6f4a31835f15ad6d4", "sha256": "34f9b995fc1957860b0e904e08c7ef532feb784e03912b4fd3008d2c6fabf315" }, "downloads": -1, "filename": "shellhistory-0.2.1.tar.gz", "has_sig": false, "md5_digest": "f679809b7fd17fe6f4a31835f15ad6d4", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<3.7", "size": 20377, "upload_time": "2018-12-26T16:45:18", "url": "https://files.pythonhosted.org/packages/77/d2/f69b7646d46e88f741597bb8829ed4fcd4f8a4c0546e09ae7423775251fa/shellhistory-0.2.1.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "811dafd18f1a08933cde71a5139c87d4", "sha256": "7c78300f56d679a6e608b7ef119fdb4d853f3cf406f2d3aba163f4ecfab4b49e" }, "downloads": -1, "filename": "shellhistory-0.2.2-py3-none-any.whl", "has_sig": false, "md5_digest": "811dafd18f1a08933cde71a5139c87d4", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<3.7", "size": 76670, "upload_time": "2019-04-30T17:45:08", "url": "https://files.pythonhosted.org/packages/26/80/c0df00140f5cb7b36ad7940cb55a56207c557957f784697d7da52876f0ee/shellhistory-0.2.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8992b546c9a49ae108e01aee717248b4", "sha256": "f6d1ca64b414ec4f6848c2aaafb764105df339f425d2576744b727c2855febab" }, "downloads": -1, "filename": "shellhistory-0.2.2.tar.gz", "has_sig": false, "md5_digest": "8992b546c9a49ae108e01aee717248b4", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<3.7", "size": 21059, "upload_time": "2019-04-30T17:45:12", "url": "https://files.pythonhosted.org/packages/4b/7d/18a4975309a77d88aefd9174703008110e2480611031700e7b0c25a8fbb8/shellhistory-0.2.2.tar.gz" } ], "0.2.3": [ { "comment_text": "", "digests": { "md5": "a99207583dc88e4ec4ff98fb180d8b8f", "sha256": "db85a7ab0c3b3ca4e632c9e68202c267ddb4ec26e0b5321223ab68cb96184d1d" }, "downloads": -1, "filename": "shellhistory-0.2.3-py3-none-any.whl", "has_sig": false, "md5_digest": "a99207583dc88e4ec4ff98fb180d8b8f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 78108, "upload_time": "2019-05-04T15:26:25", "url": "https://files.pythonhosted.org/packages/28/16/0c89c8ad0359c62cbbe829df3f7cd36742e775c16df1aa0124d56c04c416/shellhistory-0.2.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a168f1c69e440a0246aac1f6b2566a30", "sha256": "3a2cda9363b13cf1c9354c58e18b2780be93b953fd1495bafec272ec8d61ee39" }, "downloads": -1, "filename": "shellhistory-0.2.3.tar.gz", "has_sig": false, "md5_digest": "a168f1c69e440a0246aac1f6b2566a30", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 21952, "upload_time": "2019-05-04T15:26:26", "url": "https://files.pythonhosted.org/packages/51/d2/53c27b79c12348f2c02fd1502a9b718184f0a847dfe1b49d697cdb6c4b0e/shellhistory-0.2.3.tar.gz" } ], "0.2.4": [ { "comment_text": "", "digests": { "md5": "fd11f38062846f107b08be520daefe7f", "sha256": "6e7232b86c4a3a439f1307149259239ac8f914dde8b05afb9e40a2304a76e408" }, "downloads": -1, "filename": "shellhistory-0.2.4-py3-none-any.whl", "has_sig": false, "md5_digest": "fd11f38062846f107b08be520daefe7f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 37857, "upload_time": "2019-05-17T13:58:28", "url": "https://files.pythonhosted.org/packages/54/2b/1be4be5b02c0c87fb8b744c853d474812ebe292d826afc66e9092892ef38/shellhistory-0.2.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "385cc8726b6a4e9b616bdf685d060fd5", "sha256": "9d98bd66bf0989306b666b19944d1f7e7bfd2cfb04b986f9653d137d88777703" }, "downloads": -1, "filename": "shellhistory-0.2.4.tar.gz", "has_sig": false, "md5_digest": "385cc8726b6a4e9b616bdf685d060fd5", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 22674, "upload_time": "2019-05-17T13:58:29", "url": "https://files.pythonhosted.org/packages/28/c7/32ba00009c0c2928135c249e1779f218aedf51a29bec435454b8bffea804/shellhistory-0.2.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "fd11f38062846f107b08be520daefe7f", "sha256": "6e7232b86c4a3a439f1307149259239ac8f914dde8b05afb9e40a2304a76e408" }, "downloads": -1, "filename": "shellhistory-0.2.4-py3-none-any.whl", "has_sig": false, "md5_digest": "fd11f38062846f107b08be520daefe7f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 37857, "upload_time": "2019-05-17T13:58:28", "url": "https://files.pythonhosted.org/packages/54/2b/1be4be5b02c0c87fb8b744c853d474812ebe292d826afc66e9092892ef38/shellhistory-0.2.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "385cc8726b6a4e9b616bdf685d060fd5", "sha256": "9d98bd66bf0989306b666b19944d1f7e7bfd2cfb04b986f9653d137d88777703" }, "downloads": -1, "filename": "shellhistory-0.2.4.tar.gz", "has_sig": false, "md5_digest": "385cc8726b6a4e9b616bdf685d060fd5", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 22674, "upload_time": "2019-05-17T13:58:29", "url": "https://files.pythonhosted.org/packages/28/c7/32ba00009c0c2928135c249e1779f218aedf51a29bec435454b8bffea804/shellhistory-0.2.4.tar.gz" } ] }