Sunday, March 28, 2021

Money Tracking Spreadsheet

 I'm now 9 years into a money tracking spreadsheet that I've designed in Google sheets, with over 27K individual transactions. As this has been super useful to me (and fun, it's kind of my hobby, tbh) around my finanical journey towards FIRE (Financial Independence, Retire Early - ok probably not the latter), I thought I'd share this out with the greater community.


This spreadsheet is designed around
  • yealry budget for "have to" expenses
  • 2 week discrentionary sprints, as that's my pay period (I'm sure it can be adapted to different frequencies)
  • categorization of transactions using US BLS standards
  • extrapolation of discretionary expenses, to get a better picture of where your money is going
I do as many transactions using credit card as possible (as long as it doesn't cost more than paying with cash). I don't like cash because allows me to see exactly where my money goes. Also, don't discount the value of rewards.

Anyway, feel free to start with my instructions document and my template spreadsheet.


Thursday, March 25, 2021

power(shell), corruption & lies: Building command line arguments

I hate typing long command lines to command line utilities. Invariably I will get one obscure path wrong and spend an hour with a copy / pasted command line in notepad to split out the components and figure out what I screwed up this time.

A lot of those long typing jobs have to do with feeding a bunch of file or directory names to an .exe

    foo_the_bar.exe --blort first\dir second\dir third\dir hey\heres\a\filename.txt

If I only had a tool that I could use to generate that list of directories and filenames.

powershell and Invoke-Expression (iex to it's friends) to the frickin' rescue.

  1. Write a powershell expression using Get-ChildItem (gci), Where-Object (?) and Select-Object (select) to build your list of things. Use -join ' ' to space separate the list of things

    PS c:\users\kpk> (gci c:\my\dir -recurse | ?{ $_.FullName -match 'some.*criteria$' } | select -expand FullName) -join ' '

  2. Use string interpolation to embed that expression with the name of the .exe you want to run. In my case, I was using cloc to (duh) Count Lines Of Code.

    PS c:\users\kpk> "cloc $((gci c:\my\dir -recurse | ?{ $_.FullName -match 'some.*criteria$' } | select -expand FullName) -join ' ')"

  3. Run that expression a few times to make sure you're happy with it. Add some command line arguments as needed.
  4. Use iex (Invoke-Expression) to run that beautiful mess.

Let's unpack the expression a bit

    PS c:\users\kpk> (gci c:\my\dir -recurse | ?{ $_.FullName -match 'some.*criteria$' } | select -expand FullName) -join ' '

  1. gci c:\my\dir -recurse |

    gci (Get-ChildItem) recurses through a directory structure. It's more complicated than that, but things often are.

  2. ?{ $_.FullName -match 'some.*criteria$' } |

    ? (Where-Object) will test each produced file & directory for a criteria. In this case, a regular expression. Only the worthy shall pass.

  3. select -expand FullName

    select (Select-Object) extracts the FullName property from the produced collection of objects and expands it to a list

  4. -join ' '

    I need that list turned into a single flattened string with space separation, because cloc wants space separation. Other command line utilities want other kind of formatting (prefixed by a magic argument, comma separated, etc.). -join's your friend here.
Once all of this is looking good, and you've prefixed it with the name of the command you want to run, iex takes care of the rest.

Never let a human do a job that a robot can do better. Ok, maybe not 'Never', but mostly. Sometimes.... Whatever.