Hacker News new | ask | show | jobs
by adrianmonk 2180 days ago
You can also use a "here document"

    help() {
      cat <<'EOH'
    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.
    EOH
    }
If the indentation bugs you, you can use a simpler sed trick to remove leading space so that you can indent it as desired:

    help() {
      sed -e 's/    //' <<'EOH'
        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.
    EOH
    }
6 comments

Or just a multiline string:

  #!/bin/bash
  USAGE="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() {
    echo "$USAGE"
  }
This is my standard approach which is cleaner for putting the documentation at the very top of the file like the linked article.
Thank you! I had no idea that multiline strings were valid bash.
It's the same logic that allows you to type:

git commit -m "First line of commit

Second line of commit"

That's a multi-line string in bash.

Woah, I had no idea multiline strings were even a thing in Bash, I've been using heredocs for help messages since forever!

Do you know if these are portable?

As far as I know. The POSIX spec[1] simply declares that in single quotes all characters will be preserved exactly, except for single quotes, which aren't allowed. Likewise, for double quotes, except that it also performs expansions ($) and allows escaping (\).

[1]https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V...

That's exactly what I do. For others who were not aware that multi-line strings can be used, this is POSIX-compatible (most of my shell scripts are executed by `dash`).
This is one (useful!) interpretation of "code should be self-documenting". Just put the documentation into strings.
You can also use add a hyphen ( <<-EOF ) to suppress leading tabs but not spaces. https://linuxhint.com/bash-heredoc-tutorial/
I've always avoided that for fear that my or someone else's editor will accidentally replace the tabs with space. Mixed is not a common configuration, these days.
This makes me want to use this just to get people to fix their broken editors.
Oh, that's nice! And in spite of the labeling on that page, it doesn't seem to be a BASHism; it at least works in dash, too.
And ksh.
Seriously, bash has too many obscure features.
Ruby and Perl have `here` docs as well.

And Ruby 2.5 has an enhancement which preserves leading whitespace.

a commonly used feature that has been a part of the unix standard since before "bash" only meant to hit something with a heavy object, while linus was getting his diaper changed is not an "obscure feature."

a five year old took his first aware car ride, and at a gas station saw the trunk of the car next to theirs open. he said "seriously, bmw has too many obscure features." after all, a car for him was where you put the baby seat. and why would you put that in a compartment with no windows or air, that's too small to even fit a baby seat.

did you enjoy the ride?

I believe the point of the article's method is that it allows you to document your script with code comments, and then reuse the same text for help output
The neat thing about not indenting it is that you can make use of your editor's text-width auto-wrapping. For example, if you have it set to 80 columns, indenting it would make the text-width of the help text 76 in your case.

Also, putting the help text in code like this instead of a comment allows one to expand $0 so that the command name in the help text always matches the filename and path used in the invocation.

But now the sed line bugs me ;)
Or just write it in Python.
Python is terrible at one liners. The sed is much more compact.
Multiline strings means you don't need sed or anything.