mirror of
https://github.com/jbranchaud/til
synced 2026-03-04 15:08:45 +00:00
Compare commits
4 Commits
2cc52bf8bc
...
copilot/up
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c58bfbb37f | ||
|
|
9b5af6a535 | ||
|
|
62d194f492 | ||
|
|
7a7a0faf94 |
34
README.md
34
README.md
@@ -6,11 +6,11 @@ A collection of concise write-ups on small things I learn day to day across a
|
|||||||
variety of languages and technologies. These are things that don't really
|
variety of languages and technologies. These are things that don't really
|
||||||
warrant a full blog post. These are things I've picked up by [Learning In
|
warrant a full blog post. These are things I've picked up by [Learning In
|
||||||
Public™](https://dev.to/jbranchaud/how-i-built-a-learning-machine-45k9) and
|
Public™](https://dev.to/jbranchaud/how-i-built-a-learning-machine-45k9) and
|
||||||
working across different projects via [VisualMode](https://www.visualmode.dev/).
|
pairing with smart people at Hashrocket.
|
||||||
|
|
||||||
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
||||||
|
|
||||||
_1743 TILs and counting..._
|
_1715 TILs and counting..._
|
||||||
|
|
||||||
See some of the other learning resources I work on:
|
See some of the other learning resources I work on:
|
||||||
|
|
||||||
@@ -131,7 +131,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Clean Up Your Brew Installations](brew/clean-up-your-brew-installations.md)
|
- [Clean Up Your Brew Installations](brew/clean-up-your-brew-installations.md)
|
||||||
- [Configure Brew Environment Variables](brew/configure-brew-environment-variables.md)
|
- [Configure Brew Environment Variables](brew/configure-brew-environment-variables.md)
|
||||||
- [Export List Of Everything Installed By Brew](brew/export-list-of-everything-installed-by-brew.md)
|
- [Export List Of Everything Installed By Brew](brew/export-list-of-everything-installed-by-brew.md)
|
||||||
- [Install From Nonstandard Brewfile](brew/install-from-nonstandard-brewfile.md)
|
|
||||||
- [Install Go Packages In Brewfile](brew/install-go-packages-in-brewfile.md)
|
- [Install Go Packages In Brewfile](brew/install-go-packages-in-brewfile.md)
|
||||||
- [List All Services Managed By Brew](brew/list-all-services-managed-by-brew.md)
|
- [List All Services Managed By Brew](brew/list-all-services-managed-by-brew.md)
|
||||||
|
|
||||||
@@ -158,10 +157,8 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
|
|
||||||
### Claude Code
|
### Claude Code
|
||||||
|
|
||||||
- [Allow Edits From The Start](claude-code/allow-edits-from-the-start.md)
|
|
||||||
- [Monitor Usage Limits From CLI](claude-code/monitor-usage-limits-from-cli.md)
|
- [Monitor Usage Limits From CLI](claude-code/monitor-usage-limits-from-cli.md)
|
||||||
- [Open Current Prompt In Default Editor](claude-code/open-current-prompt-in-default-editor.md)
|
- [Open Current Prompt In Default Editor](claude-code/open-current-prompt-in-default-editor.md)
|
||||||
- [Resume Specific Session](claude-code/resume-specific-session.md)
|
|
||||||
|
|
||||||
### Clojure
|
### Clojure
|
||||||
|
|
||||||
@@ -351,7 +348,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Count Number Of Commits On A Branch](git/count-number-of-commits-on-a-branch.md)
|
- [Count Number Of Commits On A Branch](git/count-number-of-commits-on-a-branch.md)
|
||||||
- [Create A New Branch With Git Switch](git/create-a-new-branch-with-git-switch.md)
|
- [Create A New Branch With Git Switch](git/create-a-new-branch-with-git-switch.md)
|
||||||
- [Delete All Untracked Files](git/delete-all-untracked-files.md)
|
- [Delete All Untracked Files](git/delete-all-untracked-files.md)
|
||||||
- [Determine Absolute Path Of Top-Level Project Directory](git/determine-absolute-path-of-top-level-project-directory.md)
|
|
||||||
- [Determine The Hash Id For A Blob](git/determine-the-hash-id-for-a-blob.md)
|
- [Determine The Hash Id For A Blob](git/determine-the-hash-id-for-a-blob.md)
|
||||||
- [Diffing With Patience](git/diffing-with-patience.md)
|
- [Diffing With Patience](git/diffing-with-patience.md)
|
||||||
- [Dropping Commits With Git Rebase](git/dropping-commits-with-git-rebase.md)
|
- [Dropping Commits With Git Rebase](git/dropping-commits-with-git-rebase.md)
|
||||||
@@ -427,7 +423,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Show What Is In A Stash](git/show-what-is-in-a-stash.md)
|
- [Show What Is In A Stash](git/show-what-is-in-a-stash.md)
|
||||||
- [Single Key Presses in Interactive Mode](git/single-key-presses-in-interactive-mode.md)
|
- [Single Key Presses in Interactive Mode](git/single-key-presses-in-interactive-mode.md)
|
||||||
- [Skip A Bad Commit When Bisecting](git/skip-a-bad-commit-when-bisecting.md)
|
- [Skip A Bad Commit When Bisecting](git/skip-a-bad-commit-when-bisecting.md)
|
||||||
- [Skip Git Hooks As Needed](git/skip-git-hooks-as-needed.md)
|
|
||||||
- [Skip Pre-Commit Hooks](git/skip-pre-commit-hooks.md)
|
- [Skip Pre-Commit Hooks](git/skip-pre-commit-hooks.md)
|
||||||
- [Staging Changes Within Vim](git/staging-changes-within-vim.md)
|
- [Staging Changes Within Vim](git/staging-changes-within-vim.md)
|
||||||
- [Staging Stashes Interactively](git/staging-stashes-interactively.md)
|
- [Staging Stashes Interactively](git/staging-stashes-interactively.md)
|
||||||
@@ -505,7 +500,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
|
|
||||||
### Heroku
|
### Heroku
|
||||||
|
|
||||||
- [Check Ruby Version For Production App](heroku/check-ruby-version-for-production-app.md)
|
|
||||||
- [Connect To A Database By Color](heroku/connect-to-a-database-by-color.md)
|
- [Connect To A Database By Color](heroku/connect-to-a-database-by-color.md)
|
||||||
- [Deploy A Review App To A Different Stack](heroku/deploy-a-review-app-to-a-different-stack.md)
|
- [Deploy A Review App To A Different Stack](heroku/deploy-a-review-app-to-a-different-stack.md)
|
||||||
- [Diagnose Problems In A Heroku Postgres Database](heroku/diagnose-problems-in-a-heroku-postgres-database.md)
|
- [Diagnose Problems In A Heroku Postgres Database](heroku/diagnose-problems-in-a-heroku-postgres-database.md)
|
||||||
@@ -551,7 +545,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Focus The URL Bar](internet/focus-the-url-bar.md)
|
- [Focus The URL Bar](internet/focus-the-url-bar.md)
|
||||||
- [Get Random Images From Unsplash](internet/get-random-images-from-unsplash.md)
|
- [Get Random Images From Unsplash](internet/get-random-images-from-unsplash.md)
|
||||||
- [Grab The RSS Feed For A Substack Blog](internet/grab-the-rss-feed-for-a-substack-blog.md)
|
- [Grab The RSS Feed For A Substack Blog](internet/grab-the-rss-feed-for-a-substack-blog.md)
|
||||||
- [Hide Overflowing Text For Google Sheets Column](internet/hide-overflowing-text-for-google-sheets-column.md)
|
|
||||||
- [Search Tweets By Author](internet/search-tweets-by-author.md)
|
- [Search Tweets By Author](internet/search-tweets-by-author.md)
|
||||||
- [Show All Pivotal Stories With Blockers](internet/show-all-pivotal-stories-with-blockers.md)
|
- [Show All Pivotal Stories With Blockers](internet/show-all-pivotal-stories-with-blockers.md)
|
||||||
- [Verify Site Ownership With DNS Record](internet/verify-site-ownership-with-dns-record.md)
|
- [Verify Site Ownership With DNS Record](internet/verify-site-ownership-with-dns-record.md)
|
||||||
@@ -720,7 +713,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Capture Screenshot To Clipboard From CLI](mac/capture-screenshot-to-clipboard-from-cli.md)
|
- [Capture Screenshot To Clipboard From CLI](mac/capture-screenshot-to-clipboard-from-cli.md)
|
||||||
- [Check Network Quality Stats From The Command Line](mac/check-network-quality-stats-from-the-command-line.md)
|
- [Check Network Quality Stats From The Command Line](mac/check-network-quality-stats-from-the-command-line.md)
|
||||||
- [Clean Up Old Homebrew Files](mac/clean-up-old-homebrew-files.md)
|
- [Clean Up Old Homebrew Files](mac/clean-up-old-homebrew-files.md)
|
||||||
- [Control Which Monitor App Switcher Appears On](mac/control-which-monitor-app-switcher-appears-on.md)
|
|
||||||
- [Convert An HEIC Image File To JPG](mac/convert-an-heic-image-file-to-jpg.md)
|
- [Convert An HEIC Image File To JPG](mac/convert-an-heic-image-file-to-jpg.md)
|
||||||
- [Default Screenshot Location](mac/default-screenshot-location.md)
|
- [Default Screenshot Location](mac/default-screenshot-location.md)
|
||||||
- [Detect How Long A User Has Been Idle](mac/detect-how-long-a-user-has-been-idle.md)
|
- [Detect How Long A User Has Been Idle](mac/detect-how-long-a-user-has-been-idle.md)
|
||||||
@@ -754,12 +746,9 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
|
|
||||||
- [Create Umbrella Task For All Test Tasks](mise/create-umbrella-task-for-all-test-tasks.md)
|
- [Create Umbrella Task For All Test Tasks](mise/create-umbrella-task-for-all-test-tasks.md)
|
||||||
- [List The Files Being Loaded By Mise](mise/list-the-files-being-loaded-by-mise.md)
|
- [List The Files Being Loaded By Mise](mise/list-the-files-being-loaded-by-mise.md)
|
||||||
- [Look In Ruby Version Dotfile](mise/look-in-ruby-version-dotfile.md)
|
|
||||||
- [Override Your Project Mise File](mise/override-your-project-mise-file.md)
|
|
||||||
- [Preserve Color Output For Task Command](mise/preserve-color-output-for-task-command.md)
|
- [Preserve Color Output For Task Command](mise/preserve-color-output-for-task-command.md)
|
||||||
- [Read Existing Dot Env File Into Env Vars](mise/read-existing-dot-env-file-into-env-vars.md)
|
- [Read Existing Dot Env File Into Env Vars](mise/read-existing-dot-env-file-into-env-vars.md)
|
||||||
- [Run A Command With Specific Tool Version](mise/run-a-command-with-specific-tool-version.md)
|
- [Run A Command With Specific Tool Version](mise/run-a-command-with-specific-tool-version.md)
|
||||||
- [Search Through Bin Paths For Tool Locations](mise/search-through-bin-paths-for-tool-locations.md)
|
|
||||||
|
|
||||||
### MongoDB
|
### MongoDB
|
||||||
|
|
||||||
@@ -865,7 +854,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Clear The Screen In psql](postgres/clear-the-screen-in-psql.md)
|
- [Clear The Screen In psql](postgres/clear-the-screen-in-psql.md)
|
||||||
- [Clear The Screen In psql (2)](postgres/clear-the-screen-in-psql-2.md)
|
- [Clear The Screen In psql (2)](postgres/clear-the-screen-in-psql-2.md)
|
||||||
- [Compute Hashes With pgcrypto](postgres/compute-hashes-with-pgcrypto.md)
|
- [Compute Hashes With pgcrypto](postgres/compute-hashes-with-pgcrypto.md)
|
||||||
- [Compute Median Instead Of Average](postgres/compute-median-instead-of-average.md)
|
|
||||||
- [Compute The Levenshtein Distance Of Two Strings](postgres/compute-the-levenshtein-distance-of-two-strings.md)
|
- [Compute The Levenshtein Distance Of Two Strings](postgres/compute-the-levenshtein-distance-of-two-strings.md)
|
||||||
- [Compute The md5 Hash Of A String](postgres/compute-the-md5-hash-of-a-string.md)
|
- [Compute The md5 Hash Of A String](postgres/compute-the-md5-hash-of-a-string.md)
|
||||||
- [Concatenate Strings With A Separator](postgres/concatenate-strings-with-a-separator.md)
|
- [Concatenate Strings With A Separator](postgres/concatenate-strings-with-a-separator.md)
|
||||||
@@ -1034,12 +1022,8 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
|
|
||||||
- [Access Instance Variables](python/access-instance-variables.md)
|
- [Access Instance Variables](python/access-instance-variables.md)
|
||||||
- [Break Debugger On First Line Of Program](python/break-debugger-on-first-line-of-program.md)
|
- [Break Debugger On First Line Of Program](python/break-debugger-on-first-line-of-program.md)
|
||||||
- [Check If Package Is Installed With Pip](python/check-if-package-is-installed-with-pip.md)
|
|
||||||
- [Create A Dummy DataFrame In Pandas](python/create-a-dummy-dataframe-in-pandas.md)
|
- [Create A Dummy DataFrame In Pandas](python/create-a-dummy-dataframe-in-pandas.md)
|
||||||
- [Dunder Methods](python/dunder-methods.md)
|
- [Dunder Methods](python/dunder-methods.md)
|
||||||
- [Install With PIP For Specific Interpreter](python/install-with-pip-for-specific-interpreter.md)
|
|
||||||
- [Iterate First N Items From Enumerable](python/iterate-first-n-items-from-enumerable.md)
|
|
||||||
- [Load A File Into The Python REPL](python/load-a-file-into-the-python-repl.md)
|
|
||||||
- [Override The Boolean Context Of A Class](python/override-the-boolean-context-of-a-class.md)
|
- [Override The Boolean Context Of A Class](python/override-the-boolean-context-of-a-class.md)
|
||||||
- [Store And Access Immutable Data In A Tuple](python/store-and-access-immutable-data-in-a-tuple.md)
|
- [Store And Access Immutable Data In A Tuple](python/store-and-access-immutable-data-in-a-tuple.md)
|
||||||
- [Test A Function With Pytest](python/test-a-function-with-pytest.md)
|
- [Test A Function With Pytest](python/test-a-function-with-pytest.md)
|
||||||
@@ -1078,12 +1062,9 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Cast Common Boolean-Like Values To Booleans](rails/cast-common-boolean-like-values-to-booleans.md)
|
- [Cast Common Boolean-Like Values To Booleans](rails/cast-common-boolean-like-values-to-booleans.md)
|
||||||
- [Change The Nullability Of A Column](rails/change-the-nullability-of-a-column.md)
|
- [Change The Nullability Of A Column](rails/change-the-nullability-of-a-column.md)
|
||||||
- [Change The Time Zone Offset Of A DateTime Object](rails/change-the-time-zone-offset-of-a-datetime-object.md)
|
- [Change The Time Zone Offset Of A DateTime Object](rails/change-the-time-zone-offset-of-a-datetime-object.md)
|
||||||
- [Check How Database Is Configured](rails/check-how-database-is-configured.md)
|
|
||||||
- [Check If ActiveRecord Update Fails](rails/check-if-activerecord-update-fails.md)
|
- [Check If ActiveRecord Update Fails](rails/check-if-activerecord-update-fails.md)
|
||||||
- [Check If Any Records Have A Null Value](rails/check-if-any-records-have-a-null-value.md)
|
- [Check If Any Records Have A Null Value](rails/check-if-any-records-have-a-null-value.md)
|
||||||
- [Check Specific Attributes On ActiveRecord Array](rails/check-specific-attributes-on-activerecord-array.md)
|
- [Check Specific Attributes On ActiveRecord Array](rails/check-specific-attributes-on-activerecord-array.md)
|
||||||
- [Check The Current Named Log Level](rails/check-the-current-named-log-level.md)
|
|
||||||
- [Clean Up Memory Hungry Rails Console Processes](rails/clean-up-memory-hungry-rails-console-processes.md)
|
|
||||||
- [Code Statistics For An Application](rails/code-statistics-for-an-application.md)
|
- [Code Statistics For An Application](rails/code-statistics-for-an-application.md)
|
||||||
- [Columns With Default Values Are Nil On Create](rails/columns-with-default-values-are-nil-on-create.md)
|
- [Columns With Default Values Are Nil On Create](rails/columns-with-default-values-are-nil-on-create.md)
|
||||||
- [Comparing DateTimes Down To Second Precision](rails/comparing-datetimes-down-to-second-precision.md)
|
- [Comparing DateTimes Down To Second Precision](rails/comparing-datetimes-down-to-second-precision.md)
|
||||||
@@ -1437,7 +1418,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Limit Split](ruby/limit-split.md)
|
- [Limit Split](ruby/limit-split.md)
|
||||||
- [List The Running Ruby Version](ruby/list-the-running-ruby-version.md)
|
- [List The Running Ruby Version](ruby/list-the-running-ruby-version.md)
|
||||||
- [Listing Local Variables](ruby/listing-local-variables.md)
|
- [Listing Local Variables](ruby/listing-local-variables.md)
|
||||||
- [Make A Long String Of Text Readable](ruby/make-a-long-string-of-text-readable.md)
|
|
||||||
- [Make An Executable Ruby Script](ruby/make-an-executable-ruby-script.md)
|
- [Make An Executable Ruby Script](ruby/make-an-executable-ruby-script.md)
|
||||||
- [Make Structs Easier To Use With Keyword Initialization](ruby/make-structs-easier-to-use-with-keyword-initialization.md)
|
- [Make Structs Easier To Use With Keyword Initialization](ruby/make-structs-easier-to-use-with-keyword-initialization.md)
|
||||||
- [Map With Index Over An Array](ruby/map-with-index-over-an-array.md)
|
- [Map With Index Over An Array](ruby/map-with-index-over-an-array.md)
|
||||||
@@ -1491,7 +1471,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Single And Double Quoted String Notation](ruby/single-and-double-quoted-string-notation.md)
|
- [Single And Double Quoted String Notation](ruby/single-and-double-quoted-string-notation.md)
|
||||||
- [Skip Specific CVEs When Auditing Your Bundle](ruby/skip-specific-cves-when-auditing-your-bundle.md)
|
- [Skip Specific CVEs When Auditing Your Bundle](ruby/skip-specific-cves-when-auditing-your-bundle.md)
|
||||||
- [Skip The Front Of An Array With Drop](ruby/skip-the-front-of-an-array-with-drop.md)
|
- [Skip The Front Of An Array With Drop](ruby/skip-the-front-of-an-array-with-drop.md)
|
||||||
- [Specify Default For Data Definition](ruby/specify-default-for-data-definition.md)
|
|
||||||
- [Specify Dependencies For A Rake Task](ruby/specify-dependencies-for-a-rake-task.md)
|
- [Specify Dependencies For A Rake Task](ruby/specify-dependencies-for-a-rake-task.md)
|
||||||
- [Specify How Random Array#sample Is](ruby/specify-how-random-array-sample-is.md)
|
- [Specify How Random Array#sample Is](ruby/specify-how-random-array-sample-is.md)
|
||||||
- [Split A Float Into Its Integer And Decimal](ruby/split-a-float-into-its-integer-and-decimal.md)
|
- [Split A Float Into Its Integer And Decimal](ruby/split-a-float-into-its-integer-and-decimal.md)
|
||||||
@@ -1579,7 +1558,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Kill Other Connections To A Session](tmux/kill-other-connections-to-a-session.md)
|
- [Kill Other Connections To A Session](tmux/kill-other-connections-to-a-session.md)
|
||||||
- [Kill The Current Session](tmux/kill-the-current-session.md)
|
- [Kill The Current Session](tmux/kill-the-current-session.md)
|
||||||
- [List All Key Bindings](tmux/list-all-key-bindings.md)
|
- [List All Key Bindings](tmux/list-all-key-bindings.md)
|
||||||
- [List Processes Running Across All Session](tmux/list-processes-running-across-all-sessions.md)
|
|
||||||
- [List Sessions](tmux/list-sessions.md)
|
- [List Sessions](tmux/list-sessions.md)
|
||||||
- [Open New Splits To The Current Directory](tmux/open-new-splits-to-the-current-directory.md)
|
- [Open New Splits To The Current Directory](tmux/open-new-splits-to-the-current-directory.md)
|
||||||
- [Open New Window With A Specific Directory](tmux/open-new-window-with-a-specific-directory.md)
|
- [Open New Window With A Specific Directory](tmux/open-new-window-with-a-specific-directory.md)
|
||||||
@@ -1626,7 +1604,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
### Unix
|
### Unix
|
||||||
|
|
||||||
- [All The Environment Variables](unix/all-the-environment-variables.md)
|
- [All The Environment Variables](unix/all-the-environment-variables.md)
|
||||||
- [Apply Successive Filters To Lines In Less](unix/apply-successive-filters-to-lines-in-less.md)
|
|
||||||
- [Authorize A cURL Request](unix/authorize-a-curl-request.md)
|
- [Authorize A cURL Request](unix/authorize-a-curl-request.md)
|
||||||
- [Cat A File With Line Numbers](unix/cat-a-file-with-line-numbers.md)
|
- [Cat A File With Line Numbers](unix/cat-a-file-with-line-numbers.md)
|
||||||
- [Cat Files With Color Using Bat](unix/cat-files-with-color-using-bat.md)
|
- [Cat Files With Color Using Bat](unix/cat-files-with-color-using-bat.md)
|
||||||
@@ -1657,11 +1634,9 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Curling For Headers](unix/curling-for-headers.md)
|
- [Curling For Headers](unix/curling-for-headers.md)
|
||||||
- [Curling With Basic Auth Credentials](unix/curling-with-basic-auth-credentials.md)
|
- [Curling With Basic Auth Credentials](unix/curling-with-basic-auth-credentials.md)
|
||||||
- [Determine ipv4 And ipv6 Public IP Addresses](unix/determine-ipv4-and-ipv6-public-ip-addresses.md)
|
- [Determine ipv4 And ipv6 Public IP Addresses](unix/determine-ipv4-and-ipv6-public-ip-addresses.md)
|
||||||
- [Diff Two Files In Unified Format](unix/diff-two-files-in-unified-format.md)
|
|
||||||
- [Different Ways To Generate A v4 UUID](unix/different-ways-to-generate-a-v4-uuid.md)
|
- [Different Ways To Generate A v4 UUID](unix/different-ways-to-generate-a-v4-uuid.md)
|
||||||
- [Display All The Terminal Colors](unix/display-all-the-terminal-colors.md)
|
- [Display All The Terminal Colors](unix/display-all-the-terminal-colors.md)
|
||||||
- [Display Free Disk Space](unix/display-free-disk-space.md)
|
- [Display Free Disk Space](unix/display-free-disk-space.md)
|
||||||
- [Display Line Numbers While Using Less](unix/display-line-numbers-while-using-less.md)
|
|
||||||
- [Display The Contents Of A Directory As A Tree](unix/display-the-contents-of-a-directory-as-a-tree.md)
|
- [Display The Contents Of A Directory As A Tree](unix/display-the-contents-of-a-directory-as-a-tree.md)
|
||||||
- [Do A Dry Run Of An rsync](unix/do-a-dry-run-of-an-rsync.md)
|
- [Do A Dry Run Of An rsync](unix/do-a-dry-run-of-an-rsync.md)
|
||||||
- [Do Not Overwrite Existing Files](unix/do-not-overwrite-existing-files.md)
|
- [Do Not Overwrite Existing Files](unix/do-not-overwrite-existing-files.md)
|
||||||
@@ -1687,7 +1662,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Fix Previous Command With fc](unix/fix-previous-command-with-fc.md)
|
- [Fix Previous Command With fc](unix/fix-previous-command-with-fc.md)
|
||||||
- [Fix Shim Path After asdf Upgrade](unix/fix-shim-path-after-asdf-upgrade.md)
|
- [Fix Shim Path After asdf Upgrade](unix/fix-shim-path-after-asdf-upgrade.md)
|
||||||
- [Fix Unlinked Node Binaries With asdf](unix/fix-unlinked-node-binaries-with-asdf.md)
|
- [Fix Unlinked Node Binaries With asdf](unix/fix-unlinked-node-binaries-with-asdf.md)
|
||||||
- [Format And Display Small Amounts Of Columnar Data](unix/format-and-display-small-amounts-of-columnar-data.md)
|
|
||||||
- [Forward Multiple Ports Over SSH](unix/forward-multiple-ports-over-ssh.md)
|
- [Forward Multiple Ports Over SSH](unix/forward-multiple-ports-over-ssh.md)
|
||||||
- [Generate A SAML Key And Certificate Pair](unix/generate-a-saml-key-and-certificate-pair.md)
|
- [Generate A SAML Key And Certificate Pair](unix/generate-a-saml-key-and-certificate-pair.md)
|
||||||
- [Generate A Sequence Of Numbered Items](unix/generate-a-sequence-of-numbered-items.md)
|
- [Generate A Sequence Of Numbered Items](unix/generate-a-sequence-of-numbered-items.md)
|
||||||
@@ -1771,7 +1745,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Show A File Preview When Searching With FZF](unix/show-a-file-preview-when-searching-with-fzf.md)
|
- [Show A File Preview When Searching With FZF](unix/show-a-file-preview-when-searching-with-fzf.md)
|
||||||
- [Show Disk Usage For The Current Directory](unix/show-disk-usage-for-the-current-directory.md)
|
- [Show Disk Usage For The Current Directory](unix/show-disk-usage-for-the-current-directory.md)
|
||||||
- [Show The Size Of Everything In A Directory](unix/show-the-size-of-everything-in-a-directory.md)
|
- [Show The Size Of Everything In A Directory](unix/show-the-size-of-everything-in-a-directory.md)
|
||||||
- [Show Tree View Of Processes And Subprocesses](unix/show-tree-view-of-processes-and-subprocesses.md)
|
|
||||||
- [Skip Paging If Output Fits On Screen With Less](unix/skip-paging-if-output-fits-on-screen-with-less.md)
|
- [Skip Paging If Output Fits On Screen With Less](unix/skip-paging-if-output-fits-on-screen-with-less.md)
|
||||||
- [SSH Escape Sequences](unix/ssh-escape-sequences.md)
|
- [SSH Escape Sequences](unix/ssh-escape-sequences.md)
|
||||||
- [SSH With Port Forwarding](unix/ssh-with-port-forwarding.md)
|
- [SSH With Port Forwarding](unix/ssh-with-port-forwarding.md)
|
||||||
@@ -1787,7 +1760,6 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Unrestrict Where ripgrep Searches](unix/unrestrict-where-ripgrep-searches.md)
|
- [Unrestrict Where ripgrep Searches](unix/unrestrict-where-ripgrep-searches.md)
|
||||||
- [Update Package Versions Known By asdf Plugin](unix/update-package-versions-known-by-asdf-plugin.md)
|
- [Update Package Versions Known By asdf Plugin](unix/update-package-versions-known-by-asdf-plugin.md)
|
||||||
- [Use fzf To Change Directories](unix/use-fzf-to-change-directories.md)
|
- [Use fzf To Change Directories](unix/use-fzf-to-change-directories.md)
|
||||||
- [Use Negative Lookbehind Matching With ripgrep](unix/use-negative-lookbehind-matching-with-ripgrep.md)
|
|
||||||
- [Use Regex Pattern Matching With Grep](unix/use-regex-pattern-matching-with-grep.md)
|
- [Use Regex Pattern Matching With Grep](unix/use-regex-pattern-matching-with-grep.md)
|
||||||
- [View A Web Page In The Terminal](unix/view-a-web-page-in-the-terminal.md)
|
- [View A Web Page In The Terminal](unix/view-a-web-page-in-the-terminal.md)
|
||||||
- [View The Source For A Brew Formula](unix/view-the-source-for-a-brew-formula.md)
|
- [View The Source For A Brew Formula](unix/view-the-source-for-a-brew-formula.md)
|
||||||
@@ -2084,7 +2056,7 @@ I shamelessly stole this idea from
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
© 2015-2026 Josh Branchaud
|
© 2015-2025 Josh Branchaud
|
||||||
|
|
||||||
This repository is licensed under the MIT license. See `LICENSE` for
|
This repository is licensed under the MIT license. See `LICENSE` for
|
||||||
details.
|
details.
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ tasks:
|
|||||||
notes:sync:
|
notes:sync:
|
||||||
desc: Sync latest changes from the notes submodule
|
desc: Sync latest changes from the notes submodule
|
||||||
cmds:
|
cmds:
|
||||||
- cd {{.NOTES_DIR}} && git checkout main && git pull
|
- git submodule update --remote {{.NOTES_DIR}}
|
||||||
|
- cd {{.NOTES_DIR}} && git checkout main
|
||||||
silent: false
|
silent: false
|
||||||
|
|
||||||
notes:open:
|
notes:open:
|
||||||
@@ -60,6 +61,11 @@ tasks:
|
|||||||
cmds:
|
cmds:
|
||||||
- git status
|
- git status
|
||||||
|
|
||||||
|
notes:pull:
|
||||||
|
desc: Pull latest changes (alias for sync)
|
||||||
|
cmds:
|
||||||
|
- task notes:sync
|
||||||
|
|
||||||
notes:diff:
|
notes:diff:
|
||||||
desc: Show uncommitted changes in notes
|
desc: Show uncommitted changes in notes
|
||||||
dir: '{{.NOTES_DIR}}'
|
dir: '{{.NOTES_DIR}}'
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
# Install From Nonstandard Brewfile
|
|
||||||
|
|
||||||
When you want to install the packages listed in the `Brewfile` for your current
|
|
||||||
project (or dotfiles), you can run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ brew bundle
|
|
||||||
```
|
|
||||||
|
|
||||||
And `brew` knows to look for and use the `Brewfile` in the current directory.
|
|
||||||
|
|
||||||
If, however, you are trying to run `brew bundle` for a `Brewfile` located
|
|
||||||
somewhere besides the current directory *OR* you want to target a file with a
|
|
||||||
non-standard name (like
|
|
||||||
[`Brewfile.personal`](https://github.com/jbranchaud/dotfiles/blob/main/Brewfile.personal)),
|
|
||||||
then you can use the `--file` flag.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ brew bundle --file Brewfile.personal
|
|
||||||
```
|
|
||||||
|
|
||||||
This is what I do [here in my `dotfiles`
|
|
||||||
repo](https://github.com/jbranchaud/dotfiles/blob/b053f6251cae7ed52f698fc2a2c40ba82c5881b0/installer/mac-setup.sh#L42-L48).
|
|
||||||
|
|
||||||
See `man brew` and find the section on `brew bundle` for more details.
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# Allow Edits From The Start
|
|
||||||
|
|
||||||
A common pattern for me when using Claude Code is that I start it up in a
|
|
||||||
project, I prompt it with a question or feature spec, it either comes up with a
|
|
||||||
plan or just starts working, and as soon as it is ready to make its first edits
|
|
||||||
to a file, it prompts me something like:
|
|
||||||
|
|
||||||
```
|
|
||||||
Do you want to make this edit to Taskfile.yml?
|
|
||||||
❯ 1. Yes
|
|
||||||
2. Yes, allow all edits during this session (shift+tab)
|
|
||||||
3. Type here to tell Claude what to do differently
|
|
||||||
```
|
|
||||||
|
|
||||||
That's a nice default so that I don't get surprised by Claude Code editing a
|
|
||||||
bunch of files.
|
|
||||||
|
|
||||||
However, if I'm in a git-backed project and I'm going into a session intending
|
|
||||||
to make edits, then I can skip the formalities. I can tell Claude Code when
|
|
||||||
starting up the session that edits are allowed.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ claude --permission-mode acceptEdits
|
|
||||||
```
|
|
||||||
|
|
||||||
When I do this, I'll see the following indicator below the prompt input field:
|
|
||||||
|
|
||||||
```
|
|
||||||
⏵⏵ accept edits on (shift+tab to cycle)
|
|
||||||
```
|
|
||||||
|
|
||||||
If I've already started `claude` but I forgot to specify that permission mode, I
|
|
||||||
can also toggle right into _accept edits_ by hitting `Shift+Tab`.
|
|
||||||
|
|
||||||
[source](https://www.youtube.com/watch?v=_IK18goX4X8)
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# Resume Specific Session
|
|
||||||
|
|
||||||
There are a few different ways to resume a [Claude
|
|
||||||
Code](https://code.claude.com/docs/en/overview) session.
|
|
||||||
|
|
||||||
First, if I have exited a session for the current project and I want to pick
|
|
||||||
back up with that most recent one, then I can use `claude --continue`.
|
|
||||||
|
|
||||||
If I have had a few recent sessions for the current project and I want to
|
|
||||||
remember what they were and pick up where I left off with one of them, then I
|
|
||||||
can use `claude --resume` (with no argument). That will open a picker where I
|
|
||||||
can browser through a summary of the recent sessions based on their starting
|
|
||||||
prompt. The one I pick is the session that will be resumed.
|
|
||||||
|
|
||||||
Finally, if I have grabbed a specific session ID (UUID) during the session from
|
|
||||||
the `/status` output, then I can reference that value directly.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ claude --resume 92170532-be31-4a91-b2a9-025b8fa78232
|
|
||||||
```
|
|
||||||
|
|
||||||
See `claude --help` for more details.
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# Determine Absolute Path Of Top-Level Project Directory
|
|
||||||
|
|
||||||
The `git rev-parse` command is a git plumbing command for parsing different
|
|
||||||
kinds of things in git into a canonical form that can be used in a deterministic
|
|
||||||
way by scripts. I would typically think of using it to work with branch names,
|
|
||||||
tags, and other kinds of refs.
|
|
||||||
|
|
||||||
There is a handy, sorta off-label use for it in determining the absolute path of
|
|
||||||
the root directory for the current git repository. Use the `--show-toplevel`
|
|
||||||
flag with no other arguments.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ git rev-parse --show-toplevel
|
|
||||||
/Users/lastword/dev/jbranchaud/til
|
|
||||||
```
|
|
||||||
|
|
||||||
Here, I am in the local copy of [my TIL repo](https://github.com/jbranchaud/til). This command gives me the absolute
|
|
||||||
path of the top-level directory where that `.git` directory resides.
|
|
||||||
|
|
||||||
This is useful for scripts that need to orient themselves to the current
|
|
||||||
project's top-level directory regardless of what directory they are being
|
|
||||||
executed from. This is useful for things like a git hook script or monorepos
|
|
||||||
with scripts located in a specific sub-project directory.
|
|
||||||
|
|
||||||
Also worth mentioning is the `--show-superproject-working-tree` flag. In my TIL
|
|
||||||
repo, I have a private repository included as a submodule. Within that directory
|
|
||||||
`--show-toplevel` will produce the absolute path to the submodule. If I instead
|
|
||||||
want the absolute path of the _super project_ (in this case TIL), then I can use
|
|
||||||
this other flag.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ git rev-parse --show-toplevel
|
|
||||||
/Users/lastword/dev/jbranchaud/til/notes
|
|
||||||
|
|
||||||
❯ git rev-parse --show-superproject-working-tree
|
|
||||||
/Users/lastword/dev/jbranchaud/til
|
|
||||||
```
|
|
||||||
|
|
||||||
See `man git-rev-parse` for more details.
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# Skip Git Hooks As Needed
|
|
||||||
|
|
||||||
Projects have Git hooks configured for all sorts of reasons. Most common are
|
|
||||||
`pre-commit` hooks which verify certain aspects of the contents of a commit.
|
|
||||||
A `pre-commit` hook could check that the tests all pass, that the changes don't
|
|
||||||
include any debugging statements, and so forth. There are all kinds of hooks
|
|
||||||
though, like `pre-rebase` and `post-checkout`.
|
|
||||||
|
|
||||||
These hooks can sometimes get in the way and we may need to skip or disable them
|
|
||||||
on a one-off basis.
|
|
||||||
|
|
||||||
Several Git commands offer a `--no-verify` flag which can skip running the hook
|
|
||||||
associated with that command.
|
|
||||||
|
|
||||||
- `git commit --no-verify` (skips `pre-commit` and `commit-msg` hooks)
|
|
||||||
- `git push --no-verify` (skips `pre-push` hook)
|
|
||||||
- `git merge --no-verify` (skips `pre-merge-commit` hook)
|
|
||||||
- `git am --no-verify` (skips `applypatch-msg` and `pre-applypatch` hooks)
|
|
||||||
|
|
||||||
If you look in the `.git/hooks` directory, there are several other hooks not
|
|
||||||
covered by the above. So, what if I am doing an action like `git checkout` and I
|
|
||||||
want to skip the `post-checkout` hook?
|
|
||||||
|
|
||||||
I can override the `hooksPath` config for that one command with the `-c` flag.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ git -c core.hooksPath=/dev/null checkout ...
|
|
||||||
```
|
|
||||||
|
|
||||||
By setting it to `/dev/null`, it will find *no* hooks available, so none will be
|
|
||||||
executed for this command.
|
|
||||||
|
|
||||||
See `man git-config` for more details on `core.hooksPath`.
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# Check Ruby Version For Production App
|
|
||||||
|
|
||||||
While deploying a fresh Rails app to Heroku recently, I ran into an issue. The
|
|
||||||
`it` block argument wasn't working despite being on Ruby 4.0. Or so I thought.
|
|
||||||
|
|
||||||
Running the following command reported the Ruby version of that Heroku server
|
|
||||||
instance:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ heroku run -- ruby --version
|
|
||||||
Running ruby --version on ⬢ my-app... up, run.3090
|
|
||||||
ruby 3.3.9 (2025-07-24 revision f5c772fc7c) [x86_64-linux]
|
|
||||||
```
|
|
||||||
|
|
||||||
I was on `3.3.9` which must have been the fallback default at the time.
|
|
||||||
|
|
||||||
Though I had set the Ruby version in my `.ruby-version` file, I had neglected to
|
|
||||||
specify it in the `Gemfile` as well. Once I added it to the `Gemfile` and
|
|
||||||
redeployed, my Heroku server instance was running the expected version of Ruby.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ heroku run -- ruby --version
|
|
||||||
Running ruby --version on ⬢ my-app... up, run.5353
|
|
||||||
ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [x86_64-linux]
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: because [I have set `HEROKU_ORGANIZATION` and
|
|
||||||
`HEROKU_APP`](set-default-team-and-app-for-project.md) in my environment
|
|
||||||
(`.envrc`) for the local copy of the app, I don't need to specify those when
|
|
||||||
running the `heroku run` command above.
|
|
||||||
|
|
||||||
See `heroku run --help` for more details.
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# Hide Overflowing Text For Google Sheets Column
|
|
||||||
|
|
||||||
I imported a big CSV into a new Google Sheets document. This included a
|
|
||||||
"Description" column with many of the descriptions varying between 50 and 80
|
|
||||||
characters. The bottom line is that the description column was flowing over the
|
|
||||||
top of the columns next to it. Instead of expanding the width of that column as
|
|
||||||
far as the largest description, I wanted to hide the _overflow_.
|
|
||||||
|
|
||||||
The way to do this in Google Sheets is to highlight the entire column by
|
|
||||||
clicking on the column grouping. Then under the _Format_ menu item is a
|
|
||||||
_Wrapping_ submenu. The _Clip_ option is what I was looking for because it clips
|
|
||||||
the text that gets shown at the edge of the column.
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Control Which Monitor App Switcher Appears On
|
|
||||||
|
|
||||||
For the most part when I hit `cmd+tab` (and `cmd+shift+tab`) to switch between
|
|
||||||
apps, the visual switcher UI (which shows a row of the open apps) appears on my
|
|
||||||
main monitor. However, sometimes I will be hitting `cmd+tab` and nothing shows
|
|
||||||
up on my main monitor. I look to the right at my side monitor and there is the
|
|
||||||
app switcher UI.
|
|
||||||
|
|
||||||
Why is it appearing over there all of a sudden?
|
|
||||||
|
|
||||||
The reason is that the app switcher UI is anchored to the same screen where the
|
|
||||||
doc is located. Though the doc defaults to my main monitor, if I access the doc
|
|
||||||
from the side monitor, now it is anchored there.
|
|
||||||
|
|
||||||
To switch it back, I just have to make the doc slide up on my main monitor by
|
|
||||||
running my mouse down to the bottom of that screen.
|
|
||||||
|
|
||||||
The switch up was because I accidentally accessed the doc on my side monitor
|
|
||||||
without realizing.
|
|
||||||
|
|
||||||
[source](https://superuser.com/a/744680)
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# Look In Ruby Version Dotfile
|
|
||||||
|
|
||||||
Newer versions of [`mise`](https://mise.jdx.dev/dev-tools/) specifically only
|
|
||||||
look for tool versions in `mise.toml` as well as the asdf `.tool-versions` file.
|
|
||||||
A lot of Ruby projects use the `.ruby-version` file to indicate the Ruby version
|
|
||||||
of a project. To continue to use the `.ruby-version` file instead of migrating
|
|
||||||
to `mise.toml`, you need to tell `mise` that you prefer to use the idiomatic
|
|
||||||
version file.
|
|
||||||
|
|
||||||
I added the following line to my
|
|
||||||
[`~/.config/mise/config.toml`](https://github.com/jbranchaud/dotfiles/commit/8edeb7a9c53500e89e88b4079cbd1859ebebcbda)
|
|
||||||
file:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
idiomatic_version_file_enable_tools = ["ruby"]
|
|
||||||
```
|
|
||||||
|
|
||||||
Now, whenever `mise` is looking for the specified Ruby version of a project, it
|
|
||||||
will also look for `.ruby-version`.
|
|
||||||
|
|
||||||
Here is a [full list of idomatic version files supported by
|
|
||||||
`mise`](https://mise.jdx.dev/configuration.html#idiomatic-version-files).
|
|
||||||
|
|
||||||
See
|
|
||||||
[`idiomatic_version_file_enable_tools`](https://mise.jdx.dev/configuration/settings.html#idiomatic_version_file_enable_tools)
|
|
||||||
as well as the [Ruby-specific documentation](https://mise.jdx.dev/lang/ruby.html#ruby-version-and-gemfile-support)
|
|
||||||
for more details.
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# Override Your Project Mise File
|
|
||||||
|
|
||||||
A project I'm working on has a version-controlled `.mise.toml` file in it. Some
|
|
||||||
changes were made to that recently that introduce some env vars that conflict
|
|
||||||
with my setup. If I make edits to that file, then I have a modified version of
|
|
||||||
`.mise.toml` sitting in my Git working copy.
|
|
||||||
|
|
||||||
```
|
|
||||||
# .mise.toml
|
|
||||||
[env]
|
|
||||||
CONFIG_SETTING = "project"
|
|
||||||
```
|
|
||||||
|
|
||||||
Instead, I can rely on the loading precedence rules of `mise` to override those
|
|
||||||
project settings with my individual settings. I can do that with the
|
|
||||||
`.mise.local.toml` file which is played on top of any `mise` configuration from
|
|
||||||
files further down the precedence chain.
|
|
||||||
|
|
||||||
```
|
|
||||||
# .mise.local.toml
|
|
||||||
[env]
|
|
||||||
CONFIG_SETTING = "override"
|
|
||||||
```
|
|
||||||
|
|
||||||
Assuming I have `mise` setup with my shell environment to automatically load in
|
|
||||||
these files, I can now check what takes precedence:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ echo $CONFIG_SETTING
|
|
||||||
override
|
|
||||||
```
|
|
||||||
|
|
||||||
Make sure `.mise.local.toml` is included in the `.gitignore` file to avoid
|
|
||||||
checking in your personal environment overrides.
|
|
||||||
|
|
||||||
To be sure about what files are loaded and in what order, give `mise cfg` a try.
|
|
||||||
I discuss that in more detail in [List The Files Being Loaded By Mise](list-the-files-being-loaded-by-mise.md).
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# Search Through Bin Paths For Tool Locations
|
|
||||||
|
|
||||||
The `mise bin-paths` command will list all the bin paths that are managed by
|
|
||||||
`mise`. When you tell `mise` to install a tool, it installs a specific version
|
|
||||||
at a location where its binaries can be made accessible on the system path.
|
|
||||||
|
|
||||||
While `mise ls` is useful for seeing what is installed by `mise` and at what
|
|
||||||
version, the `bin-paths` command can tell you where those tool installations
|
|
||||||
with their binaries are located.
|
|
||||||
|
|
||||||
Combine this with `grep` or `rg` to narrow down the results to tools by a
|
|
||||||
specific name:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ mise bin-paths | rg 'neovim'
|
|
||||||
/Users/lastword/.local/share/mise/installs/npm-neovim/5.4.0/bin
|
|
||||||
/Users/lastword/.local/share/mise/installs/pipx-neovim-remote/2.5.1/bin
|
|
||||||
/Users/lastword/.local/share/mise/installs/neovim/0.11.6/bin
|
|
||||||
```
|
|
||||||
|
|
||||||
I can then look in one of these directories to see the one or more binaries that
|
|
||||||
they include. For instance, here is what is in the `node` bin path:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ ls /Users/lastword/.local/share/mise/installs/node/22.22.0/bin
|
|
||||||
./ ../ claude@ corepack@ node* npm* npx@
|
|
||||||
```
|
|
||||||
|
|
||||||
See `mise bin-paths --help` for more details.
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# Compute Median Instead Of Average
|
|
||||||
|
|
||||||
One of the first aggregate functions we might use in PostgreSQL, besides `sum`,
|
|
||||||
is `avg`.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
select avg(book_count) as average_books_read
|
|
||||||
from (
|
|
||||||
select users.id, count(books.id) as book_count
|
|
||||||
from users
|
|
||||||
left join books
|
|
||||||
on books.user_id = users.id
|
|
||||||
where books.read_in_year = 2025
|
|
||||||
group by users.id
|
|
||||||
) as user_book_counts;
|
|
||||||
```
|
|
||||||
|
|
||||||
This computes the average of the set of values which sums them all up
|
|
||||||
and divides by the count. The average (maybe you've heard this also called the
|
|
||||||
_mean_) is not always the best way to understand data, especially when there are
|
|
||||||
outliers.
|
|
||||||
|
|
||||||
Instead, we might want to compute the _median_ value of our set of data. There
|
|
||||||
is no easily identifiable `median` aggregate function. Instead, we can use
|
|
||||||
`percentile_cont` with a value of `0.5`. This gets us the 50th percentile of our
|
|
||||||
set of data which is the definition of the _median_.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
select percentile_cont(0.5) within group (
|
|
||||||
order by book_count
|
|
||||||
) as median_books_read
|
|
||||||
from (
|
|
||||||
select users.id, count(books.id) as book_count
|
|
||||||
from users
|
|
||||||
left join books on books.user_id = users.id and books.read_in_year = 2025
|
|
||||||
group by users.id
|
|
||||||
) as user_book_counts;
|
|
||||||
```
|
|
||||||
|
|
||||||
The full syntax for `percentile_cont` is `percentile_cong(precision) within
|
|
||||||
group (order by ...)` because this is an aggregiate that has to work with an
|
|
||||||
ordered-set of data.
|
|
||||||
|
|
||||||
[source](https://www.postgresql.org/docs/current/functions-aggregate.html)
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
# Check If Package Is Installed With Pip
|
|
||||||
|
|
||||||
I recently installed PyTorch, but when I tried using it, I was getting an error
|
|
||||||
about `numpy` not being installed. I was kind of surprised by that because I
|
|
||||||
thought I would have already had that.
|
|
||||||
|
|
||||||
I wanted to check, so I asked with `pip show`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ python3 -m pip show numpy
|
|
||||||
WARNING: Package(s) not found: numpy
|
|
||||||
```
|
|
||||||
|
|
||||||
I can even list everything that is installed with `pip` using `pip list` like
|
|
||||||
so:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ python3 -m pip list
|
|
||||||
Package Version Build
|
|
||||||
------------------ --------- -----
|
|
||||||
certifi 2026.1.4
|
|
||||||
cffi 2.0.0
|
|
||||||
charset-normalizer 3.4.4
|
|
||||||
click 8.3.1
|
|
||||||
commonmark 0.9.1
|
|
||||||
cryptography 46.0.3
|
|
||||||
docutils 0.22.4
|
|
||||||
filelock 3.24.2
|
|
||||||
fsspec 2026.2.0
|
|
||||||
idna 3.11
|
|
||||||
Jinja2 3.1.6
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
I then installed `numpy` (`python3 -m pip install numpy`) and how I can use `pip
|
|
||||||
show` again to confirm that.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ python3 -m pip show numpy
|
|
||||||
Name: numpy
|
|
||||||
Version: 2.4.2
|
|
||||||
Summary: Fundamental package for array computing in Python
|
|
||||||
Home-page: https://numpy.org
|
|
||||||
Author: Travis E. Oliphant et al.
|
|
||||||
Author-email:
|
|
||||||
License-Expression: BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0
|
|
||||||
Location: /Users/lastword/.local/share/mise/installs/python/3.12.12/lib/python3.12/site-packages
|
|
||||||
Requires:
|
|
||||||
Required-by:
|
|
||||||
```
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Install With PIP For Specific Interpreter
|
|
||||||
|
|
||||||
The `pip` module can be invoked for any of its commands, such as install, using
|
|
||||||
a specific Python interpreter like so:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ python3 -m pip install black
|
|
||||||
```
|
|
||||||
|
|
||||||
This avoid ambiguity between the version of Python I am using and version of the
|
|
||||||
package manager I'm using.
|
|
||||||
|
|
||||||
Similarly if I need to upgrade `pip`, I can do the following:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ python3 -m pip install --upgrade pip
|
|
||||||
```
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# Iterate First N Items From Enumerable
|
|
||||||
|
|
||||||
As I'm working through the 2nd chapter of [Build a Large Language Model (from
|
|
||||||
scratch)](https://still.visualmode.dev/blogmarks/227), I came across a code
|
|
||||||
example processing a dictionary of words. This example used a for loop to print
|
|
||||||
out each dictionary entry until an index of 50 was reached on then it did a
|
|
||||||
`break`.
|
|
||||||
|
|
||||||
This struck me as an odd way to grab and process N items from a list. I did some
|
|
||||||
searching and found `itertools` which provides
|
|
||||||
[`islice`](https://docs.python.org/3/library/itertools.html#itertools.islice).
|
|
||||||
|
|
||||||
```python
|
|
||||||
from itertools import islice
|
|
||||||
|
|
||||||
# preprocess words from a file into a word list
|
|
||||||
all_words = ... # not shown here
|
|
||||||
|
|
||||||
vocab = {token: integer for integer, token in enumerate(all_words)}
|
|
||||||
for item in islice(enumerate(vocab.items()), 50):
|
|
||||||
print(item)
|
|
||||||
```
|
|
||||||
|
|
||||||
The `islice` function is a better approach because the intention (to grab the
|
|
||||||
first 50 things) is encoded in the function call rather than buried in a loop
|
|
||||||
body. It also has equivalent memory efficiency to the original example because
|
|
||||||
it lazily processes the list of `vocab` items.
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# Load A File Into The Python REPL
|
|
||||||
|
|
||||||
I opened up a Python REPL to try some things out.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ python3
|
|
||||||
>>> import math
|
|
||||||
>>> math.floor(5/2)
|
|
||||||
2
|
|
||||||
```
|
|
||||||
|
|
||||||
Now, I want to reference a Python file I've been working on so that I can
|
|
||||||
manually test the behavior of what I'm building. To do this, I can import a file
|
|
||||||
by its name in the same way that I would import any module. Then I can use that
|
|
||||||
namespace for class and method references. Crucially, the file should exist in
|
|
||||||
the same directory the REPL was started from.
|
|
||||||
|
|
||||||
First, here is the file:
|
|
||||||
|
|
||||||
```python
|
|
||||||
# bpe.py
|
|
||||||
class BytePairEncoding:
|
|
||||||
def text_to_bytes(text: str) -> list[int]:
|
|
||||||
"""Convert a string to a list of byte values (0-255)"""
|
|
||||||
return list(text.encode("utf-8"))
|
|
||||||
```
|
|
||||||
|
|
||||||
Now to use it from the REPL:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ python
|
|
||||||
>>> import bpe
|
|
||||||
>>> bpe.BytePairEncoding.text_to_bytes("Gimme some bytes!")
|
|
||||||
[71, 105, 109, 109, 101, 32, 115, 111, 109, 101, 32, 98, 121, 116, 101, 115, 33]
|
|
||||||
```
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
# Check How Database Is Configured
|
|
||||||
|
|
||||||
While making some adjustments to the database connection string (`DATABASE_URL`)
|
|
||||||
for a pre-production Rails environment, we wanted to check that configuration
|
|
||||||
options like `sslmode` were picked up.
|
|
||||||
|
|
||||||
From a `rails console` session I can check the live database configuration like
|
|
||||||
so:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
> ActiveRecord::Base.connection_db_config.configuration_hash
|
|
||||||
=> {
|
|
||||||
adapter: "postgresql",
|
|
||||||
encoding: "unicode",
|
|
||||||
pool: 5,
|
|
||||||
database: "my_app_development"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
I can look at the
|
|
||||||
[`configuration_hash`](https://api.rubyonrails.org/classes/ActiveRecord/DatabaseConfigurations/HashConfig.html#attribute-i-configuration_hash)
|
|
||||||
from `rails console` of my pre-prod environment to see more configuration
|
|
||||||
settings:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
> ActiveRecord::Base.connection_db_config.configuration_hash
|
|
||||||
=> {
|
|
||||||
adapter: "postgresql",
|
|
||||||
encoding: "unicode",
|
|
||||||
pool: 5,
|
|
||||||
username: "app_user",
|
|
||||||
password: "super_s3cr3t",
|
|
||||||
port: 15432,
|
|
||||||
database: "pre_prod_database",
|
|
||||||
host: "some-host-123.ondigitalocean.com",
|
|
||||||
sslmode: "verify-full"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Since I was specifically looking for the `sslmode` value, I can access that
|
|
||||||
directly:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
> ActiveRecord::Base.connection_db_config.configuration_hash[:sslmode]
|
|
||||||
=> "verify-full"
|
|
||||||
```
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
# Check The Current Named Log Level
|
|
||||||
|
|
||||||
I'm connected to a `rails console` session for an active Rails app. I want to
|
|
||||||
check the current log level.
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
> Rails.logger.level
|
|
||||||
=> 1
|
|
||||||
```
|
|
||||||
|
|
||||||
The `1` doesn't mean much to me at a glance. I can translate that to the
|
|
||||||
severity level using the `Logger::SEV_LABLE` constant.
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
[44] pry(main)> Logger::SEV_LABEL[Rails.logger.level]
|
|
||||||
=> "INFO"
|
|
||||||
```
|
|
||||||
|
|
||||||
Ah yes, `INFO`, that makes sense as the default.
|
|
||||||
|
|
||||||
I can see all the severity levels by inspecting the constant itself.
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
[45] pry(main)> Logger::SEV_LABEL
|
|
||||||
=> ["DEBUG", "INFO", "WARN", "ERROR", "FATAL", "ANY"]
|
|
||||||
```
|
|
||||||
|
|
||||||
As I convenience, I can set the label using the index, the string, or even a
|
|
||||||
symbol.
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
> Rails.logger.level
|
|
||||||
=> 1
|
|
||||||
> Rails.logger.level = "WARN"
|
|
||||||
=> "WARN"
|
|
||||||
> Rails.logger.level
|
|
||||||
=> 2
|
|
||||||
> Rails.logger.level = :debug
|
|
||||||
=> :debug
|
|
||||||
> Rails.logger.level
|
|
||||||
=> 0
|
|
||||||
```
|
|
||||||
|
|
||||||
See the [Debugging Rails Applications
|
|
||||||
guide](https://guides.rubyonrails.org/debugging_rails_applications.html#log-levels)
|
|
||||||
for more details.
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
# Clean Up Memory Hungry Rails Console Processes
|
|
||||||
|
|
||||||
I noticed (using `htop`) that a remote server hosting a Rails app had most of
|
|
||||||
its RAM being actively consumed. This was hindering my ability to run a fresh
|
|
||||||
deploy because the deploy processes had to do a ton of memory swapping which
|
|
||||||
drastically slowed the whole thing down.
|
|
||||||
|
|
||||||
With some investigation, I discovered that most of the memory was being consumed
|
|
||||||
by a handful of `rails console` processes. I didn't have any known active `rails console` processes that I was using. That combined with the dates of these
|
|
||||||
processes starting way in the past suggested to me that these were abandoned
|
|
||||||
processes that hadn't been properly cleaned up.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
server:~# ps aux | grep rails
|
|
||||||
32767 878915 0.0 0.0 1227160 936 pts/0 Ssl+ 2025 0:03 /exec rails console
|
|
||||||
32767 878942 0.9 6.5 830996 261748 pts/0 Rl+ 2025 249:51 ruby /app/bin/rails console
|
|
||||||
32767 3004097 0.0 0.0 1227160 692 pts/0 Ssl+ 2025 0:04 /exec rails console
|
|
||||||
32767 3004129 0.9 6.4 834672 257228 pts/0 Dl+ 2025 406:31 ruby /app/bin/rails console
|
|
||||||
32767 3048582 0.0 0.0 1227160 940 pts/0 Ssl+ Jan09 0:00 /exec rails console
|
|
||||||
32767 3048611 1.1 6.3 829936 253484 pts/0 Dl+ Jan09 60:50 ruby /app/bin/rails console
|
|
||||||
32767 3060033 0.0 0.0 1227160 944 pts/0 Ssl+ 2025 0:04 /exec rails console
|
|
||||||
32767 3060063 0.9 6.5 838084 260812 pts/0 Rl+ 2025 405:37 ruby /app/bin/rails console
|
|
||||||
root 3699372 0.0 0.0 7008 1300 pts/0 S+ 15:51 0:00 grep --color=auto rails
|
|
||||||
server:~# ps aux | grep 'rails console' | awk '{sum+=$6} END {print sum/1024 " MB"}'
|
|
||||||
1014.64 MB
|
|
||||||
```
|
|
||||||
|
|
||||||
As we can see by tacking on this `awk` command, these processes are consuming
|
|
||||||
1GB of memory.
|
|
||||||
|
|
||||||
Each of these is a pair of processes. A parent process (`/exec rails console`)
|
|
||||||
that kicks off and supervises the memory-hungry child process (`ruby /app/bin/rails console`).
|
|
||||||
|
|
||||||
To free up this memory, I targeted each of the parent processes with a `kill`
|
|
||||||
command one by one. For example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
server:~# kill 878915
|
|
||||||
```
|
|
||||||
|
|
||||||
I suspect that I may have left the occasional terminal tab open with one of
|
|
||||||
these `rails console` processes running and the SSH connection was getting
|
|
||||||
killed without the `rails console` getting killed with it.
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
# Make A Long String Of Text Readable
|
|
||||||
|
|
||||||
I have a paragraph of text that interpolates a couple user-specific values
|
|
||||||
before being included in an API request. Because it is being passed to an API,
|
|
||||||
it is a single-line string value. However, in the editor it is hard to read like
|
|
||||||
that because it overflows way past the edge of the viewport.
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
description = "This is the description we need to provide for #{user.name} as part of an API request dealing with compliance and registration for a service. If you need to contact them, their email is #{user.email}."
|
|
||||||
```
|
|
||||||
|
|
||||||
I'd rather make this easier on myself and others to read from the editor while
|
|
||||||
still being able to submit a single-line string to the API. That can be
|
|
||||||
accomplished with a heredoc and some combination or `gsub`, `strip`, and
|
|
||||||
`squish`.
|
|
||||||
|
|
||||||
If we are in a strictly Ruby-only context, we can use `gsub` and `strip` to
|
|
||||||
collapse line breaks and remove surrounding white space.
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
description = <<~MSG.gsub(/\s+/, ' ').strip
|
|
||||||
This is the description we need to provide for #{user.name} as part
|
|
||||||
of an API request dealing with compliance and registration for a
|
|
||||||
service. If you need to contact them, their email is #{user.email}.
|
|
||||||
MSG
|
|
||||||
#=> "This is the description we need to provide for #{user.name} as part of an API request dealing with compliance and registration for a service. If you need to contact them, their email is #{user.email}."
|
|
||||||
```
|
|
||||||
|
|
||||||
Or in a Rails context, I can instead just use `squish`:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
description = <<~MSG.squish
|
|
||||||
This is the description we need to provide for #{user.name} as part
|
|
||||||
of an API request dealing with compliance and registration for a
|
|
||||||
service. If you need to contact them, their email is #{user.email}.
|
|
||||||
MSG
|
|
||||||
#=> "This is the description we need to provide for #{user.name} as part of an API request dealing with compliance and registration for a service. If you need to contact them, their email is #{user.email}."
|
|
||||||
```
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
# Specify Default For Data Definition
|
|
||||||
|
|
||||||
Here is what a `Data` definition for the concept of a `Permission` might look
|
|
||||||
like:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
Permission = Data.define(:id, :name, :description, :enabled)
|
|
||||||
|
|
||||||
perm1 = Permission.new(
|
|
||||||
id: 123,
|
|
||||||
name: :can_edit,
|
|
||||||
description: "User is allowed to edit.",
|
|
||||||
enabled: true
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
However, as we're creating various `Permission` entities, we may find that the
|
|
||||||
vast majority of them are _enabled_ by default and so we'd like to apply `true`
|
|
||||||
as a default value.
|
|
||||||
|
|
||||||
We cannot do this directly in the `Data` definition, but we can open a block to
|
|
||||||
override the `initialize` method.
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
Permission = Data.define(:id, :name, :description, :enabled) do
|
|
||||||
def initialize(:id, :name, :description, enabled: true)
|
|
||||||
super
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
perm1 = Permission.new(
|
|
||||||
id: 123,
|
|
||||||
name: :can_edit,
|
|
||||||
description: "User is allowed to edit."
|
|
||||||
)
|
|
||||||
|
|
||||||
perm1.enabled #=> true
|
|
||||||
```
|
|
||||||
|
|
||||||
Now we're able to create a `Permission` without specifying the `enabled`
|
|
||||||
attribute and it takes on the default of `true`.
|
|
||||||
|
|
||||||
[source](https://dev.to/baweaver/new-in-ruby-32-datadefine-2819#comment-254o8)
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
# List Processes Running Across All Session
|
|
||||||
|
|
||||||
I wanted an overview of all the processes running across all the tmux sessions
|
|
||||||
that I have running on my machine right now. The `list-panes` command (with the
|
|
||||||
`-a` flag) gives me a listing of all the panes across all session of the current
|
|
||||||
tmux server.
|
|
||||||
|
|
||||||
That output on its own isn't giving me quite the info I'm looking for though.
|
|
||||||
With the `-f` (_format_) flag, I can use variables available in that context
|
|
||||||
like `session_name`, `pane_pid`, and `pane_current_command`.
|
|
||||||
|
|
||||||
I can assemble the details I want into a command like this:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ tmux list-panes -a -F "#{session_name}:#{window_index}.#{pane_index} #{pane_pid} #{pane_current_command}"
|
|
||||||
PLP:1.1 62364 zsh
|
|
||||||
TIL:1.1 62345 nvim
|
|
||||||
TIL:1.2 65838 task
|
|
||||||
TIL:2.1 11428 tmux
|
|
||||||
client-app:1.1 62373 ssh
|
|
||||||
client-app:1.2 10796 zsh
|
|
||||||
client-app:1.3 63081 zsh
|
|
||||||
client-app:2.1 61115 overmind
|
|
||||||
client-app:3.1 82608 zsh
|
|
||||||
visualmode-dev:1.1 52237 zsh
|
|
||||||
```
|
|
||||||
|
|
||||||
This gives me the details I want, but I can take it a step further by piping it
|
|
||||||
to the `column` command to improve the formatting a little:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ tmux list-panes -a -F "#{session_name}:#{window_index}.#{pane_index} #{pane_pid} #{pane_current_command}" \
|
|
||||||
| column -t
|
|
||||||
PLP:1.1 62364 zsh
|
|
||||||
TIL:1.1 62345 nvim
|
|
||||||
TIL:1.2 65838 task
|
|
||||||
TIL:2.1 11428 tmux
|
|
||||||
client-app:1.1 62373 ssh
|
|
||||||
client-app:1.2 10796 zsh
|
|
||||||
client-app:1.3 63081 zsh
|
|
||||||
client-app:2.1 61115 overmind
|
|
||||||
client-app:3.1 82608 zsh
|
|
||||||
visualmode-dev:1.1 52237 zsh
|
|
||||||
```
|
|
||||||
|
|
||||||
See `man tmux` and, in particular, the `FORMATS` section for more details.
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# Apply Successive Filters To Lines In Less
|
|
||||||
|
|
||||||
Let's say I've opened a large Rails log file with `less`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ less logs/development.log
|
|
||||||
```
|
|
||||||
|
|
||||||
I have an idea of what I'm looking for, but there is way more noise than signal.
|
|
||||||
I can start to filter out some of the noise. The `&` command starts a filter
|
|
||||||
prompt. If I start to filter by something like `INSERT INTO`, then a ton of
|
|
||||||
lines disappear leaving just those matching that pattern.
|
|
||||||
|
|
||||||
Scrolling through the current set of lines, I start to have a better idea of
|
|
||||||
what I'm looking for, but there is still too much noise. I can apply an
|
|
||||||
additional successive filter on the remaining lines by hitting `&` again and
|
|
||||||
entering in another pattern -- e.g. `GoodJob`.
|
|
||||||
|
|
||||||
Now I only see lines that contain both `INSERT INTO` and `GoodJob` somewhere in
|
|
||||||
them.
|
|
||||||
|
|
||||||
As `less` puts it:
|
|
||||||
|
|
||||||
> Multiple & commands may be entered, in which case only lines which match all
|
|
||||||
> of the patterns will be displayed.
|
|
||||||
|
|
||||||
If I want to undo all the filtering, I just need to enter an empty `&` filter
|
|
||||||
prompt and it will reset things back to displaying all lines.
|
|
||||||
|
|
||||||
> If pattern is empty (if you type & immediately followed by ENTER), any
|
|
||||||
> filtering is turned off, and all lines are displayed.
|
|
||||||
|
|
||||||
See `man less` for more details.
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
# Diff Two Files In Unified Format
|
|
||||||
|
|
||||||
The `diff` command is a standalone utility that can be used to get the
|
|
||||||
difference between two files. It is similar to what you might expect when
|
|
||||||
running `git diff` which compares two different versions of the same file. The
|
|
||||||
`diff` command predates `git` and its unified format is what became the standard
|
|
||||||
that `git` uses for its own diff implementation.
|
|
||||||
|
|
||||||
Running `diff` with two files as is gives output like the following:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ diff startup.sh startup2.sh
|
|
||||||
10,13c10,14
|
|
||||||
< declare -A SESSIONS=(
|
|
||||||
< ["TIL"]="$HOME/dev/jbranchaud/til:setup_til"
|
|
||||||
< ["PLP"]="$HOME/dev/jbranchaud/pool-league-pro:"
|
|
||||||
< ["client-app"]="$HOME/dev/client/client-app:"
|
|
||||||
---
|
|
||||||
> # Sessions will be created in the order listed here
|
|
||||||
> SESSIONS=(
|
|
||||||
> "TIL:$HOME/dev/jbranchaud/til:setup_til"
|
|
||||||
> "PLP:$HOME/dev/jbranchaud/pool-league-pro:"
|
|
||||||
> "client-app:$HOME/dev/client/client-app:"
|
|
||||||
73,74c74,75
|
|
||||||
< for session_name in TIL PLP client-app; do
|
|
||||||
< IFS=':' read -r directory setup_function <<<"${SESSIONS[$session_name]}"
|
|
||||||
---
|
|
||||||
> for session_config in "${SESSIONS[@]}"; do
|
|
||||||
> IFS=':' read -r session_name directory setup_function <<<"$session_config"
|
|
||||||
```
|
|
||||||
|
|
||||||
That's readable at a glance, but the unified format (with the `-u` flag) can
|
|
||||||
provide more context:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ diff -u startup.sh startup2.sh
|
|
||||||
--- startup.sh 2026-01-10 12:46:52
|
|
||||||
+++ startup2.sh 2026-01-10 12:48:00
|
|
||||||
@@ -7,10 +7,11 @@
|
|
||||||
|
|
||||||
# Session configurations
|
|
||||||
# Format: "session_name:directory:setup_function"
|
|
||||||
-declare -A SESSIONS=(
|
|
||||||
- ["TIL"]="$HOME/dev/jbranchaud/til:setup_til"
|
|
||||||
- ["PLP"]="$HOME/dev/jbranchaud/pool-league-pro:"
|
|
||||||
- ["client-app"]="$HOME/dev/client/client-app:"
|
|
||||||
+# Sessions will be created in the order listed here
|
|
||||||
+SESSIONS=(
|
|
||||||
+ "TIL:$HOME/dev/jbranchaud/til:setup_til"
|
|
||||||
+ "PLP:$HOME/dev/jbranchaud/pool-league-pro:"
|
|
||||||
+ "client-app:$HOME/dev/client/client-app:"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Setup function for TIL session
|
|
||||||
@@ -70,8 +71,8 @@
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Create sessions in order
|
|
||||||
- for session_name in TIL PLP client-app; do
|
|
||||||
- IFS=':' read -r directory setup_function <<<"${SESSIONS[$session_name]}"
|
|
||||||
+ for session_config in "${SESSIONS[@]}"; do
|
|
||||||
+ IFS=':' read -r session_name directory setup_function <<<"$session_config"
|
|
||||||
create_session "$session_name" "$directory" "$setup_function"
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
Here we get additional context like surrounding lines and file name details.
|
|
||||||
|
|
||||||
While this is useful on its own, it also has the added benefit of making the
|
|
||||||
output compatible with other tools we may already be using. For instance, I'm
|
|
||||||
already using [delta](https://github.com/dandavison/delta) as my [git pager](https://github.com/jbranchaud/dotfiles/blob/main/gitconfig#L51) and [git differ](https://github.com/jbranchaud/dotfiles/blob/main/gitconfig#L139).
|
|
||||||
|
|
||||||
With the unified format, I can pipe the output directly to `delta` to get a
|
|
||||||
better view of the diff that is colorized and includes syntax highlighting.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ diff -u startup.sh startup2.sh | delta
|
|
||||||
```
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# Display Line Numbers While Using Less
|
|
||||||
|
|
||||||
Including line numbers while viewing files with `less` can provide useful
|
|
||||||
context for understanding where you are within the file. This is especially true
|
|
||||||
if you've used `&` to filter down to lines that match a pattern.
|
|
||||||
|
|
||||||
You can start `less` with line numbers with the `-N` flag (or `--LINE-NUMBERS`
|
|
||||||
if you really want to spell it out).
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ less -N log/development.log
|
|
||||||
```
|
|
||||||
|
|
||||||
If you've already started up `less` and wish you had included line numbers,
|
|
||||||
there is no reason to restart it with the flag. Instead, toggle the line numbers
|
|
||||||
option on within the `less` process. To do this, type `-N`. It will prompt you
|
|
||||||
with `Constantly display line numbers (press RETURN)`. Hit enter and line
|
|
||||||
numbers will appear to the left of each line in the file.
|
|
||||||
|
|
||||||
Similarly, to toggle line numbers back off within `less`, hit `-n` (lower-case
|
|
||||||
`n`), accept the prompt, and back off they go.
|
|
||||||
|
|
||||||
Both of these (`-N`/`-n`) are options being set (toggled) via the `-` command.
|
|
||||||
There are many other options like these that can be configured within a `less`
|
|
||||||
session in the same way.
|
|
||||||
|
|
||||||
See `man less` and find the `-` command and the available `OPTIONS`.
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# Format And Display Small Amounts Of Columnar Data
|
|
||||||
|
|
||||||
In [_List Processes Running Across All (tmux)
|
|
||||||
Sessions](tmux/list-processes-running-across-all-sessions.md), I showed an
|
|
||||||
example of piping some data from `tmux` to the `column -t` command to nicely format
|
|
||||||
and display the columnar data as a table. By default is uses spaces as the
|
|
||||||
delimiter.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ tmux list-panes -a -F "#{session_name}:#{window_index}.#{pane_index} #{pane_pid} #{pane_current_command}" \
|
|
||||||
| column -t
|
|
||||||
|
|
||||||
PLP:1.1 62364 zsh
|
|
||||||
TIL:1.1 62345 nvim
|
|
||||||
TIL:1.2 65838 task
|
|
||||||
TIL:2.1 11428 tmux
|
|
||||||
client-app:1.1 62373 ssh
|
|
||||||
client-app:1.2 10796 zsh
|
|
||||||
client-app:1.3 63081 zsh
|
|
||||||
client-app:2.1 61115 overmind
|
|
||||||
client-app:3.1 82608 zsh
|
|
||||||
visualmode-dev:1.1 52237 zsh
|
|
||||||
```
|
|
||||||
|
|
||||||
This can be useful for formatting data from all kinds of commands and tools.
|
|
||||||
Sometimes the columns of data are separated by something other than spaces. For
|
|
||||||
instance, here is some git branch information (for my [dotfiles
|
|
||||||
repo](https://github.com/jbranchaud/dotfiles)) separated by the `|` character.
|
|
||||||
To format that with `column`, I need to also include the `-s '|'` flag to
|
|
||||||
override the delimiter.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ git for-each-ref --format='%(refname:short)|%(authordate:short)|%(authorname)' refs/heads/ \
|
|
||||||
| column -t -s '|'
|
|
||||||
|
|
||||||
claude/sync-dotfiles-011CUP87cRV6c51eEi3Chg99 2025-10-22 jbranchaud
|
|
||||||
jb/add-rhubarb-for-fugitive-github-browse 2025-11-02 jbranchaud
|
|
||||||
jb/fix-hardcoded-paths 2025-11-02 jbranchaud
|
|
||||||
jb/set-nvim-to-default-manpager 2025-10-19 jbranchaud
|
|
||||||
main 2026-01-10 jbranchaud
|
|
||||||
master 2025-10-30 Dorian Karter
|
|
||||||
my-dotfiles 2025-11-01 jbranchaud
|
|
||||||
upstream-master 2026-01-01 Dorian Karter
|
|
||||||
```
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# Show Tree View Of Processes And Subprocesses
|
|
||||||
|
|
||||||
Though you can cobble together a command on a MacOS Unix system to output a
|
|
||||||
hierarchical tree view of a parent process and its descendent subprocesses, it
|
|
||||||
is easier to [`brew install pstree`](https://github.com/FredHucht/pstree) and
|
|
||||||
use that.
|
|
||||||
|
|
||||||
Here is what I see when I run it for a _pid_ that corresponds to a `tmux`
|
|
||||||
session that I have running locally:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
❯ pstree 61690
|
|
||||||
-+= 61690 lastword tmux new-session -d -s TIL -c /Users/lastword/dev/jbranchaud/til
|
|
||||||
|--= 63081 lastword /bin/zsh
|
|
||||||
|-+= 11428 lastword zsh
|
|
||||||
| \-+= 48511 lastword pstree 61690
|
|
||||||
| \--- 48512 root ps -axwwo user,pid,ppid,pgid,command
|
|
||||||
|-+= 62345 lastword zsh
|
|
||||||
| \--= 06031 lastword claude
|
|
||||||
|--= 62364 lastword /bin/zsh
|
|
||||||
|-+= 62373 lastword zsh
|
|
||||||
| \--= 64407 lastword ssh my-app-staging
|
|
||||||
|-+= 61115 lastword /bin/zsh
|
|
||||||
| \-+= 61579 lastword overmind start -f Procfile.dev
|
|
||||||
| \--- 61586 lastword tmux -C -L overmind-my-app-abc123 new -n web -s my-app -P -F %overmind-process #{pane_id} web #{pane_pid} /var/folders/zc/abc123/T/overmin
|
|
||||||
|--= 52237 lastword /bin/zsh
|
|
||||||
|--= 82608 lastword /bin/zsh
|
|
||||||
\--= 10796 lastword /bin/zsh
|
|
||||||
```
|
|
||||||
|
|
||||||
I was looking for a frozen `claude` process that was part of this session. And I
|
|
||||||
found it about halfway down that list -- `06031`. Now I can run `kill` on that
|
|
||||||
process as needed.
|
|
||||||
|
|
||||||
For some additional context, I initially found the _pid_ for the `tmux` session
|
|
||||||
by running `ps aux | grep tmux` and looking through those results.
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
# Use Negative Lookbehind Matching With ripgrep
|
|
||||||
|
|
||||||
The most straightforward way to use `ripgrep` is to hand it a pattern. It will
|
|
||||||
take that pattern and move forward through each file trying to find matches.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ rg 'TwilioClient\.new'
|
|
||||||
```
|
|
||||||
|
|
||||||
That will find all occurrences of `TwilioClient.new` in available project files.
|
|
||||||
|
|
||||||
What if that pattern is too permissive though? That is going to match on
|
|
||||||
occurrences of `TwilioClient.new` as well as things like
|
|
||||||
`LoggingTwilioClient.new`. If we want to exclude the latter, there are a few
|
|
||||||
ways to do that. One of them being the use of [the _negative lookbehind_ regex
|
|
||||||
feature](https://www.pcre.org/current/doc/html/pcre2syntax.html#SEC23) that is
|
|
||||||
available with PCRE2 (Perl-Compatible Regular Expressions).
|
|
||||||
|
|
||||||
A _negative lookbehind_ is like a standard pattern. We look forward through the
|
|
||||||
document for the base pattern (like `TwilioClient\.new`). However, once we find
|
|
||||||
that match, we then look back at the previous characters and if they match our
|
|
||||||
negative lookbehind pattern, then it is no longer a positive match.
|
|
||||||
|
|
||||||
We can use one of the following to forms to achieve this:
|
|
||||||
|
|
||||||
```
|
|
||||||
(?<!...) )
|
|
||||||
(*nlb:...) ) negative lookbehind
|
|
||||||
(*negative_lookbehind:...) )
|
|
||||||
```
|
|
||||||
|
|
||||||
For instance, here is what this looks like for our example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ rg -P '(?<!Logging)TwilioClient\.new'
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: we have to use the `-P` flag to tell `ripgrep` that we are using PCRE2
|
|
||||||
syntax. Otherwise, it assumes a simpler regex syntax that doesn't support
|
|
||||||
_negative lookbehind_.
|
|
||||||
|
|
||||||
See `man rg` for more details.
|
|
||||||
Reference in New Issue
Block a user