Skip to content

Instantly share code, notes, and snippets.

@kovetskiy
Created July 7, 2020 19:01
Show Gist options
  • Select an option

  • Save kovetskiy/a4bb510595b3a6b17bfd1bd9ac8bb4a5 to your computer and use it in GitHub Desktop.

Select an option

Save kovetskiy/a4bb510595b3a6b17bfd1bd9ac8bb4a5 to your computer and use it in GitHub Desktop.
#!/bin/bash
###
### my-script — does one thing well
###
### Usage:
### my-script <input> <output>
###
### Options:
### <input> Input file to read.
### <output> Output file to write. Use '-' for stdout.
### -h Show this message.
help() {
sed -rn 's/^### ?//;T;p' "$0"
}
if [[ $# == 0 ]] || [[ "$1" == "-h" ]]; then
help
exit 1
fi
echo Hello World
@TheFox

TheFox commented Jul 7, 2020

Copy link
Copy Markdown

This. Is. Perfect. 😍

@benhutchins

benhutchins commented Jul 7, 2020

Copy link
Copy Markdown

This doesn't actually work cross-platform, the -r option does not exist on macOS. You can do the same with awk though, just use:

awk '/^###/' "$0"

Complete script:

#!/bin/bash
###
### my-script — does one thing well
###
### Usage:
###   my-script <input> <output>
###
### Options:
###   <input>   Input file to read.
###   <output>  Output file to write. Use '-' for stdout.
###   -h        Show this message.

help() {
    awk '/^###/' "$0"
}

if [[ $# == 0 ]] || [[ "$1" == "-h" ]]; then
    help
    exit 1
fi

echo Hello World

@cvega

cvega commented Jul 7, 2020

Copy link
Copy Markdown

This doesn't actually work cross-platform, the -r option does not exist on macOS. You can do the same with awk though, just use:

Install GNU coreutils and gnu-sed on MacOS using brew install coreutils gnu-sed if you want to get closer to Linux.

@zouhair

zouhair commented Jul 7, 2020

Copy link
Copy Markdown

awk '/^###/' "$0"

awk -F'### ' '/^###/' "$0"

@brucewoodward

Copy link
Copy Markdown

That's cool but I think I'll stick with here documents.

#!/bin/bash

Help=$(cat <<-"HELP"

 my-script — does one thing well

 Usage:
   my-script <input> <output>

 Options:
   <input>   Input file to read.
   <output>  Output file to write. Use '-' for stdout.
   -h        Show this message.

HELP
)

help() {
    echo "$Help"
}

if [[ $# == 0 ]] || [[ "$1" == "-h" ]]; then
    help
    exit 1
fi

echo Hello World

@jdugan1024

Copy link
Copy Markdown

This is a really nifty approach, thanks for sharing. It's fairly obvious in retrospect but it hadn't occurred to me before!

Slight tweak, this awk solution will only print the help text, not the leading ### :

    awk -F'### ' '/^###/ { print $2 }' "$0"

@SuperSandro2000

SuperSandro2000 commented Jul 8, 2020

Copy link
Copy Markdown

Compacted:
[[ $# == 0 || "$1" == "-h" ]]

@evandrix

evandrix commented Jul 8, 2020

Copy link
Copy Markdown

This doesn't actually work cross-platform, the -r option does not exist on macOS. You can do the same with awk though, just use:

awk '/^###/' "$0"

Complete script:

#!/bin/bash
###
### my-script — does one thing well
###
### Usage:
###   my-script <input> <output>
###
### Options:
###   <input>   Input file to read.
###   <output>  Output file to write. Use '-' for stdout.
###   -h        Show this message.

help() {
    awk '/^###/' "$0"
}

if [[ $# == 0 ]] || [[ "$1" == "-h" ]]; then
    help
    exit 1
fi

echo Hello World

or you can use gsed, if you don't want to pollute the macos sed namespace

@bobrippling

Copy link
Copy Markdown

A sh compatible version, with portable sed usage

#!/bin/sh
###
### my-script — does one thing well
###
### Usage:
###   my-script <input> <output>
###
### Options:
###   <input>   Input file to read.
###   <output>  Output file to write. Use '-' for stdout.
###   -h        Show this message.

help() {
    sed -n 's/^### \?//p' "$0"
}

if [ $# -eq 0 ] || [ "$1" = "-h" ]; then
    help
    exit 1
fi

echo Hello World

@NightMachinery

NightMachinery commented Jul 8, 2020

Copy link
Copy Markdown

Complete awk version:

#!/usr/bin/env bash
###
### my-script — does one thing well
###
### Usage:
###   my-script <input> <output>
###
### Options:
###   <input>   Input file to read.
###   <output>  Output file to write. Use '-' for stdout.
###   -h        Show this message.

help() {
    awk -F'### ' '/^###/ { print $2 }' "$0"
}

if [[ $# == 0 || "$1" == "-h" ]]; then
    help
    exit 1
fi

echo Hello World

I personally use macros to add help messages to my zsh functions. It's as easy as:

mdoc-test() {
	# uses the global alias MAGIC
    mdoc Usage: sth MAGIC
    echo no
}
mdoc-test2() {
	# without global alias
    magic mdoc Usage: sth ; mret
    echo no
}

@rmNyro

rmNyro commented Jul 8, 2020

Copy link
Copy Markdown

Awesome idea, thanks very much!

@james-see

Copy link
Copy Markdown

Very cool.

ghost commented Jul 12, 2020

Copy link
Copy Markdown

That's a good idea. Awesome!

@jc00ke

jc00ke commented Jul 12, 2020

Copy link
Copy Markdown

@typebrook

typebrook commented Jul 17, 2020

Copy link
Copy Markdown

Glad someone proved this is a good strategy to write helper message, I also did it in my commonly-used script:
https://gist.github.com/typebrook/b0d2e7e67aa50298fdf8111ae7466b56#file-gist

what I did is simply print the comment at the top(except the first line to # --):
sed -Ene "/^#/ !q; 1,/^# --/ d; s/^# //p

@kovetskiy
@benhutchins

This doesn't actually work cross-platform, the -r option does not exist on macOS. You can do the same with awk though, just use:

-E works on BSD sed, so you can make it portable with sed -Ene 's/^### ?//;T;p' "$0" both on mac(BSD sed) or Linux(GNU sed).

@Qbin

Qbin commented Jul 24, 2020

Copy link
Copy Markdown

666

@snejus

snejus commented Oct 15, 2020

Copy link
Copy Markdown

Why even use the extended version?

sed -n 's/^###//p' achieves the same. Just keep the leading ### format to the help only.

sed -n '/^###/ s///p' this one's faster but a tiny bit more verbose.

and sed '/^###/!d' if you don't mind hashes. Or grep "^###"

@ivant

ivant commented Nov 29, 2023

Copy link
Copy Markdown

My version, that doesn't require multiple # (but allows more than one if you want it for stylistic reasons):

#!/bin/bash
# Usage:
#   test_usage.sh ...

print_usage_and_exit() {
  # The sed script below:
  # - Deletes the first line (shebang).
  # - Quits on the first line that doesn't start with #.
  # - Removes the '#+ ?' prefix from the string.
  sed -En '1d; /^[^#]/ q; s/^#+ ?//p;' < "$0" >&2
  exit 1
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment