|
| 1 | +# Start # |
| 2 | + |
| 3 | +The shebang indicates that this script should be executed by the bash program. |
| 4 | + |
| 5 | +```bash |
| 6 | +#!/bin/bash |
| 7 | +``` |
| 8 | + |
| 9 | +# Filenames # |
| 10 | + |
| 11 | +We want to support any type of code wrapped in Markdown, so we'll make no assumptions about the filename and extension preceding it and pass it through unmodified for use as the output filename. |
| 12 | + |
| 13 | +```bash |
| 14 | +# given a filename ending in .md, return the base filename |
| 15 | +function remove_extension { |
| 16 | + local file=$1 |
| 17 | + # file extension .md will always have three characters |
| 18 | + local extension_length=3 |
| 19 | + # old file path length |
| 20 | + local old_length=${#file} |
| 21 | + # calculate new filename length |
| 22 | + local new_length=$old_length-$extension_length |
| 23 | + # cut substring for new filename |
| 24 | + local new_filename=${file:0:$new_length} |
| 25 | + # return the new string |
| 26 | + echo "$new_filename" |
| 27 | +} |
| 28 | +``` |
| 29 | + |
| 30 | +# Processing |
| 31 | + |
| 32 | +This function uses a needlessly expanded version of [Rich Traube](https://github.com/trauber)'s clever [one-line awk routine](https://gist.github.com/trauber/4955706) to walk through the lines in the Markdown document and pass them into the output file as appropriate. |
| 33 | + |
| 34 | +```bash |
| 35 | +# strip Markdown |
| 36 | +function process_lines { |
| 37 | + # first argument is filename |
| 38 | + local file=$1 |
| 39 | + # iterate through lines with awk |
| 40 | + local awk_command=' |
| 41 | + # if it is a code block |
| 42 | + if (/^```/) { |
| 43 | + # increase backtick counter |
| 44 | + i++; |
| 45 | + # jump to next command |
| 46 | + next; |
| 47 | + } |
| 48 | + # print |
| 49 | + if ( i % 2 == 1) { |
| 50 | + print; |
| 51 | + } |
| 52 | + ' |
| 53 | + # run awk command |
| 54 | + local processed=$(awk {"$awk_command"} $file) |
| 55 | + # return code blocks only |
| 56 | + echo "$processed" |
| 57 | +} |
| 58 | +``` |
| 59 | + |
| 60 | +# Single File # |
| 61 | + |
| 62 | +Wrap the awk routine and the filename logic into a single function which can be called on any file to compile its output. |
| 63 | + |
| 64 | +```bash |
| 65 | +# compile Markdown code blocks in a file using awk |
| 66 | +function compile { |
| 67 | + # first argument is filename |
| 68 | + local file=$1 |
| 69 | + # conver to the new filename |
| 70 | + local new_filename=$(remove_extension $file "md") |
| 71 | + # log message |
| 72 | + echo "compiling $file > $new_filename" |
| 73 | + # parse file content and remove Markdown comments |
| 74 | + local compiled=$(process_lines $file) |
| 75 | + # save results to file |
| 76 | + echo "$compiled" > $new_filename |
| 77 | +} |
| 78 | +``` |
| 79 | + |
| 80 | +# Loop Through Files # |
| 81 | + |
| 82 | +Everything up until this point has been wrapped in a reusable function, but now it's time to define the script logic. Grab the files specified by an optional filename pattern (or alternatively the files in the current working directory) and run the compilation function on each. |
| 83 | + |
| 84 | +```bash |
| 85 | +# if the first argument exists, use it as the |
| 86 | +# target directory |
| 87 | +if [ $1 ]; then |
| 88 | + files=$1 |
| 89 | +# otherwise load all files in current directory |
| 90 | +else |
| 91 | + # files must end in .md and must contain TWO |
| 92 | + # dots so as to exclude regular non-source |
| 93 | + # Markdown files |
| 94 | + files=*.*.md |
| 95 | +fi |
| 96 | + |
| 97 | +# loop through files |
| 98 | +for file in $files |
| 99 | +do |
| 100 | + # compile |
| 101 | + compile $file |
| 102 | +done |
| 103 | +``` |
0 commit comments