exec-cmd powerful examples

2020-05-04 @Technology

Here I’ll showcase some of the more powerful examples of exec-cmd, my parameterized aliasing system I leverage for all sorts of frequent use.

See the repository README for the basic usage.

All the below use cases originate from the repository included commands.

Overview

Send a quick command line email

The following definition sends an email from the console via mutt. Note that any of the aliases emailsend, sendmail, or sm may be used.

emailsend,sendmail,sm  mutt -s !!subject !!recepient <<< !!body

Invoke the command with no arguments, to see the expected syntax:

$ ec sm
Required parameters: !!subject !!recepient !!body

And a working example, where ‘me’ is a mutt alias for my email address:

$ ec sm "exec-cmd test" me "Hello world"

Search for a custom, multi-line text record

The following searches the standard input for an entire (multi-line) text record. The record returned is one whose

  1. header matches the regular expression !!rec_start_regex
  2. contents match the expression !!pattern.
search_txt_record,srl   pattern=!!pattern && \
    sed -n "/!!rec_start_regex/{x;/$pattern/Ip;d}; \${x;G;/$pattern/Ip}; {H}"

(Perhaps not the most optimal sed usage, but it gets the job done.)

The use should become clearer with the following two commands that stack on top of the above. We now only expect one parameter, the !!pattern:

search_txt_list,stl    %self% search_txt_record !!pattern '^\w'
search_md_section,smd  %self% search_txt_record !!pattern '^#'

The first searches indented text list records, each beginning at the 0th column, with the remainder containing some non-word leading character (ex: space, hyphen).

The second searches a markdown section beginning with a ‘#’ character. A record continues until we encounter another leading ‘#’, which thus deliniates a new section.

An incredibly simple example of search_txt_list:

We first create input.txt with our input,

one
- alpha
- beta
- charlie
- lambda
two
  delta
  echo
  felix
  lambda 
three
    - gamma
    - hydra
    - ingrid
    - lambda

And then the invocation:

$ ec stl 
Required parameters: !!pattern

$ ec stl 'echo' < input.txt
two
  delta
  echo
  felix
  lambda

Lastly, let’s demonstrate a two-level conjunctive search, that is, the searching of a record matching !!pattern1 and !!pattern2.

Were this a scalable solution up to any n levels, we would require a more elaborate routine. However, for a pragmatic two-level case, the following hack of pure piping wizardry does the trick:

stl2    %self% stl !!pattern1 | %self% stl !!pattern2 

Note that ‘lambda’ appears in every record of the same input file, but ‘hydra’ strictly in the last:

$ ec stl2 lambda hydra < input.txt
three
    - gamma
    - hydra
    - ingrid
    - lambda

Custom word-count

The following returns the count of !!num_top_results number of most frequent words of at least !!min_chars number of characters, each with the respective count:

word_count,wc   tr -cs A-Za-z '\012' | tr A-Z a-z | \
                egrep "\<.{!!min_chars,}\>" | sort | \
                uniq -c | sort -nr | head -!!num_top_results

YouTube

View a YouTube URL !!url via mpv of a maximum height of !!maxheight:

youtube,yt  maxheight=!!maxheight && \
            mpv --ytdl-format="bestvideo[height<=$maxheight]+bestaudio/best[height<=$maxheight]" \
            !!url

Git

List the urls of all Git repositories situated under the path !!root:

git_rep_list  find !!root -regex '.*\.git/config*' -exec cat {} \; \
              | sed -n 's/.*url = \(.*\)/\1/p'

Extract a repository subfolder to a fresh repository, all contained files now at the root, history preserved:

git_split_dir  newrep=!!newrep_dir && \
               dir_prefix=!!dir_prefix && \
               git subtree split --prefix=$dir_prefix --branch=split && \
               git init --bare $newrep && \
               git push $newrep split:master && \
               git branch -D split && \
               echo "Created bare rep $newrep." && \
               echo "Next: 'rm -r' or filter out $dir_prefix/ "

The above routine:

  1. Takes parameters
    • !!newrep_dir - the path to a fresh repository
    • !!dir_prefix - the subfolder prefix in the original repository
  2. Extracts the subfolder into a temporary branch called ‘split’
  3. Initializes a new, bare repository indicated by !!newrep_dir
  4. Pushes the branch ‘split’ onto the new repository
  5. Deletes the temporary branch
  6. Leaves the original repository intact, letting you manually delete/handle the extracted subfolder however you please.

Lastly, the following command eliminates all trace of a file !!filename within the repository, along with the related history:

git_elim_file_hist  git filter-branch -f --index-filter \
                    "git rm --cached --ignore-unmatch !!filename" HEAD

Imagemagick batch resize

Shrink an image or a set of images to a maximum dimension size of !!max_size, maintaining the aspect ratio:

img_shrink_if_gt  size=!!max_size && mogrify "!!pattern[$size""x""$size"">]"

For example, ec img_shrink_if_gt 1024 '*.jpg' shrinks all jpegs in the current directory to the maximum dimensions of 1024x1024, resizing the smaller of the dimensions appropriately to maintain the aspect ratio.

Sync your config files with a repository

In the example commands you’ll find a sync routine that I will not here reproduce. It effectively invokes rsync with a series of handy parameters.

Of interest is the following command stacked on top of sync to restrict the synchronization of !!src to only the files contained within !!dest:

sync_existing_only  src="!!src" dest="!!dest" && \
                    %self% sync "$src" "$dest" \
                    --files-from=<(find "$dest" -type f -printf '%P\n')

It does this, moreover, not using the --existing rsync parameter, but the safer, faster, and more explicit --files-from, which we build via a named-pipe call to find.

This is handy, for instance, when you wish to synchronize a series of configuration files with a Git repository.

Suppose your repository exists in $HOME/config-rep. First, manually copy all config files from under your home directory to config-rep, maintaining the same directory structure.

The following exec-cmd command (not included in the repository) then synchronizes strictly the files contained within config-rep:

sync_config_rep  %self% sync_existing_only ~/ "$HOME/config-rep/" 

(No parameters are necessary upon the call to ec sync_config_rep.)

Questions, comments? Connect.