#* ABOUT display commands from the ~/.bash_history file that have comments somewhere above them (not including the time stamp). I adapted this from /eg/bash.history.comments.pss which doesn't pretty print the output. This script is actually quite useful for seeing cli incantations that I have done in the past but promptly forgotten. All that imagemagick stuff with convert and mogrify or pdf manipulations with pdfunite etc. pdfjam [latex] and what-not. I dont want to keep this stuff in the brain. This version bash.history.comments.pss only prints commands in the .bash_history file which have a comment (or multiple comment lines starting with hash) above the 'timestamp' or between the timestamp and the bash command. This is an example of a task that becomes quite tricky in [sed] Parse a bash history file which has some explanatory comments above or below the timestamp for commands. This is a format that I use in my bash history file to remind me of something that I did a while ago, and also to make it easier to search for the command. Appears to be working, and only takes about 1 second for a 35000 line history file eg: * how to use >> pep -f pars/eg/bash.history.display.pss ~/.bash_history TESTING use the helper functions in helpers.pars.sh to translate to other languages and run. * translate to python and run --- pep -f tr/translate.py.pss eg/bash.history.pss > eg/py/bash.history.pss chmod a+x eg/py/bash.history.pss cat ~/.bash_history | eg/py/bash.history.pss > test1.txt # now compare with the output from the interpreted script pep -f eg/bash.history.pss ~/.bash_history > test2.txt vimdiff test1.text test2.txt ,,, NOTES I probably should save all "convert" "mogrify" and "pdf" commands because I can never remember the syntax for them. The [pep] accumulator register is used to count how many commands are filtered. Trivial commands, like 'cd' or 'ls' are only filtered out if they dont have a comment. HISTORY 27 march 2025 adapting from bash.history.comments.pss this version tries to pretty print the comments *# begin { # the empty recordset trick to simplify the grammar rules add "recordset*"; push; } read; [\n] { # just to debug # lines; print; clear; } # parse line by line. whilenot [\n]; # ignore blank lines and empty comments "",[:space:],[#] { clear; .reparse } put; B"#".!"#" { clop; put; [#0123456789] { clear; add "timestamp:"; get; add ""; put; clear; add "timestamp*"; push; .reparse } # clear some leading comment space B" " { clop; clop; } B" " { clop; clop; } B" " { clop; } put; clear; add " "; get; put; clear; add "comment*"; push; .reparse } # tag the command as trivial if it is # for later removal. If there is a comment above it we may keep it anyway # tag as trivial all commands less than 5 characters clip; clip; clip; clip; "" { # indent clear; add " "; get; put; clear; add "trivial*"; push; .reparse } clear; get; B"blog.",B"aa.",B"ardu.", B"df ","df",B"du ",B"mv ",B"cp ",B"less ",B"vim ",B"rm ",B"mkdir ", B"find ",B"locate ",B"cd ","cd",B"ls ","ls","pwd","hist","books","bk","ho", "updatedb","bashrc","vimrc","os","cos","ccos","make" { # indent clear; add " "; get; put; clear; add "trivial*"; push; .reparse } # indent command for clarity. clear; add "\n "; get; put; clear; add "command*"; push; parse> # for debugging # add "line "; lines; add " char "; chars; add ": "; print; clear; # add "line "; lines; add ": "; print; clear; # unstack; print; stack; add "\n"; print; clear; # ---------------- # 2 tokens pop; pop; # ignore duplicated timestamps. "timestamp*timestamp*" { clear; ++; get; --; put; clear; add "timestamp*"; push; .reparse } # handle multiline comments "comment*comment*" { clear; get; add "\n"; ++; get; --; put; clear; add "comment*"; push; .reparse } # dont need because an initial recordset always exists #"record*record*","recordset*record*" { "recordset*record*" { # double space for readability clear; get; add "\n\n"; ++; get; --; put; clear; a+; # count filtered add "recordset*"; push; .reparse } # this will be compiled differently from r*r* "recordset*command*" { # clear; get; add "\n"; ++; get; --; put; clear; # just ignore commands with no comments clear; add "recordset*"; push; .reparse } "recordset*trivial*" { a+; # count filtered commands clear; add "recordset*"; push; .reparse } (eof) { # clean up trailing comments etc "recordset*timestamp*","recordset*comment*" { clear; add "recordset*record*"; push; push; .reparse } } # ------------- # 3 parse tokens pop; # remove trivial commands without comments "recordset*timestamp*trivial*" { a+; # count filtered commands clear; add "recordset*"; push; .reparse } # ignore duplicated timestamps. "timestamp*comment*timestamp*" { clear; ++; get; --; put; clear; ++; ++; get; --; put; --; clear; add "comment*timestamp*"; push; push; .reparse } # amalgamate comments before and after the timestamp "comment*timestamp*comment*" { clear; get; ++; ++; add "\n"; get; --; --; put; clear; add "comment*timestamp*"; push; push; .reparse } "comment*timestamp*command*","comment*timestamp*trivial*" { clear; add "-----------------------------------"; ++; get; --; add "\n"; get; add "\n"; ++; ++; get; --; --; put; clear; add "record*"; push; .reparse } # dont remove trivial commands with comments "timestamp*comment*command*","timestamp*comment*trivial*" { clear; add "-----------------------------------"; get; add "\n"; # switch the order to make comment precede timestamp ++; get; add "\n"; ++; get; --; --; put; clear; add "record*"; push; .reparse } "recordset*timestamp*command*" { # clear; ++; get; add "\n"; ++; get; --; put; --; clear; # just ignore commands with no comments clear; add "recordset*"; push; .reparse } # resolve commands and trivial command with comments "recordset*comment*command*","recordset*comment*trivial*" { clear; add "\n-----------------------\n"; ++; get; add "\n"; ++; get; --; put; --; clear; add "recordset*record*"; push; push; .reparse } push; push; push; (eof) { pop; pop; !"recordset*" { push; push; add "# History file did not parse well!\n"; print; clear; add "# Parse stack was: "; print; clear; unstack; add "\n"; print; quit; } "recordset*" { clear; get; add "\n# History file parsed and filtered "; add " by /eg/bash.history.display.pss \n"; add "# "; count; add " commented commands were found.\n"; print; } }