Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I want that my help message be extracted from the script itself.

#!/bin/bash
#
# foo - do things
# Author: John Doe <jhon@doe>
# ----------------------------------------------
# SYNOPSIS
#   foo [OPTIONS] FILE
# 
# DESCRIPTION
#   At vero eos et accusamus et iusto odio
#   dignissimos ducimus qui blanditiis praesenti
#   voluptatum deleniti atque corrupti quos.
# ----------------------------------------------

sed -n '/# -\+$/,/# -\+$/ p' $0

It works! It prints only what is between the two # -\+$ delimiters, inclusive. The problem is that I don't want print the delimiters.

And do you have suggestions for a man page generator with human friendly syntax?

Update: Maybe stated my problem poorly. I want to print only what is between the two lines starting with # ----- and ending with ----.

I know this solution:

sed -n '/# -\+$/,/# -\+$/ p' $0 | head -n -1 | tail -n +2

But I want a clean and elegant solution that doesn't look hackish.

share|improve this question
1  
Removing the cat/which would be cleaner, $0 already holds the full path to the binary, so sed ... $0 would do. –  Thor Sep 30 '12 at 6:55
    
@Thor a lot better... –  Kanvuanza Sep 30 '12 at 12:12
1  
shocco.sh does it similarly, but uses an additional prefix character for documentation comments. –  manatwork Oct 1 '12 at 10:06
1  
@manatwork schocco is awesome. ronn (from same author) is nice too: converts markdown to roff. –  Kanvuanza Oct 1 '12 at 12:54
add comment

6 Answers 6

up vote 2 down vote accepted

Try this please:

#!/bin/bash
#
# foo - do things
# Author: John Doe <jhon@doe>
# ----------------------------------------------
# SYNOPSIS
#   foo [OPTIONS] FILE
# 
# DESCRIPTION
#   At vero eos et accusamus et iusto odio
#   dignissimos ducimus qui blanditiis praesenti
#   voluptatum deleniti atque corrupti quos.
# ----------------------------------------------


cat `which $0` | sed -n '0,/# -\+$/d;/# -\+$/,$d;p'
share|improve this answer
    
Haha, you got it :-) –  Kanvuanza Sep 30 '12 at 1:36
    
Then it's time to go for a sleep ) –  Serge Sep 30 '12 at 1:37
add comment

You can also accomplish this with awk:

awk '/^# --/{ flag=!flag; next}; flag' file

Given that the text you are using to delimit the desired text is the same at the beginning and end, ie., # --, the normal range pattern will fail so you need to use a flag. The next statement forces awk to move to the next record, before printing the range.

share|improve this answer
    
It prints the desired output, plus two blank lines and then the cat ... line. –  Kanvuanza Sep 30 '12 at 1:50
    
I'd love to see an awk solution. –  Kanvuanza Sep 30 '12 at 1:50
    
Sorry: I misread the question... –  jasonwryan Sep 30 '12 at 1:58
    
Oh, thanks. Do you mind explain a bit? –  Kanvuanza Sep 30 '12 at 2:03
    
Updated: hope that helps. –  jasonwryan Sep 30 '12 at 3:53
show 2 more comments

You could do it pretty simply with awk:

awk -v RS='\n# -+' 'NR==2' $0

RS sets to record separator appropriately and NR==2 prints the second record.

You can remove the comment sign and extra space with gsub, e.g.:

awk -v RS='\n# -+' 'NR==2 { gsub("\n# ", "\n"); print }' $0

Update

To avoid an empty first line add \n to RS, but now the first line is not substituted by gsub, so gensub is called for:

awk -v RS='\n# -+\n' 'NR==2 { print gensub("(^|\n)# ", "\\1", "g") }' $0
share|improve this answer
    
Very understandable answer. The first line is empty, I tried to remove with gsub(/\n?\n# /, "\n") without success. –  Kanvuanza Sep 30 '12 at 12:11
    
I see what you mean, I'll add and update that fixes it. –  Thor Sep 30 '12 at 15:14
add comment

What you're needing is called a "here document." Fortunately, it's already implemented in bash. Check out the following URL http://tldp.org/LDP/abs/html/here-docs.html

You simply use the following:

cat <<end-of-message
----------------------------
message lines...
----------------------------
end-of-message

You can add a conditional at the top of your script to print that only if a parameter is input or something... like a -h option or if there are no arguments present.

Hope this helps.

share|improve this answer
1  
Sorry, I don't understand how heredocs could help me. –  Kanvuanza Sep 30 '12 at 3:36
add comment

Rather than sticking your message into the comments at the beginning of the file, you can also emulate the __DATA__ section of Perl and some other programming languages by exiting before the script reaches it:

#!/bin/sh

data=$(sed '0,/^__DATA__$/d' "$0")
printf '%s\n' "$data"

exit

__DATA__
FOO BAR BAZ
LLAMA DUCK COW

Same general idea as the other sed-based solutions, though.

share|improve this answer
    
Man, this is cool. I liked the idea of meta info (beyond comments) stored on source code. I prefer documentation on top, but sure I'll find some use for this. –  Kanvuanza Sep 30 '12 at 19:46
add comment

This might work for you (GNU sed):

 sed '/^# -\+$/,//!d;//d' $0

Explanation:

  • /^# -\+$/,//!d delete everything not between delimiters
  • //d delete the delimiters and let the remainder pass through

N.B. // reuses the latest regexp.

share|improve this answer
    
If this works will be the best solution IMO. –  Kanvuanza Oct 5 '12 at 5:34
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.