0

i have a homework to print the header of a shell script as help option using sed

The shell script (the correct answer from prof)

    #---------------------------------------------------------------------
    #   File-name: <script1.sh>
    #   Language: bash script
    #   Project: Shell Script Programming Class
    #   Description: xyz
    #   Author: iamgroot
    #---------------------------------------------------------------------
    if [ "$1" == '-h' ] ; then
        echo Help:
        sed -n '/File\-name/,/A\uthor/p' "$0" | sed "s/^#//g"
        exit 0
    fi

The output

Help:
    File-name: <script1.sh>
    Language: bash script
    Project: Shell Script Programming Class
    Description: xyz
    Author: iamgroot

I dont understand why there is \ before -name and before uthor (row 10 shell script)

Also why there is "$0" (the same row)? Any help would be appreciated

iamgroot
  • 85
  • 8
  • 3
    Your prof seems to be a noob. Have you ever tried to run the script? BTW: string comparison is done with a single `=`. `$0` is the name of the script itself. See the [manual](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#index-_00240). – ceving Jan 06 '22 at 10:40
  • 2
    Looks like prof is checking who is just copy the code without any understanding what it's doing. These `\ ` technically useless, but harmless, code runs the same with or without them. And `"$0"` will give you the path of the script, in this example `sed` will print all lines between patterns `File-name` and `Author`(including) from script and remove `#` at the beginning of the lines. – Ivan Jan 06 '22 at 10:49
  • @Ivan I actually tried to remove the `\ ` both in `File-Name` and `Author`, it's only giving me a different output when I remove it before `-name`. It prints out from `File-name` until `fi`. How is that possible? – iamgroot Jan 06 '22 at 10:55
  • 1
    @Ivan only the \u is useless, but \- is needed (otherwise, it is treated as a range) – Aserre Jan 06 '22 at 10:59
  • 2
    Also : the sed command could be simplified : `sed -n '/File\-name/,/Author/ s/^#//gp' "$0"` – Aserre Jan 06 '22 at 11:03
  • BTW: do not use single brackets, if you use just the Bash. Instead: always use double brackets. See [here](https://stackoverflow.com/q/669452/402322) for details. – ceving Jan 06 '22 at 11:44
  • @Aserre The `-` is treated as a range expression in a bracket expression only (for example, `[a-z]`). It is an ordinary character outside of bracket expression, so preceding it with the ``\`` is not needed, and probably leads to undefined behaviour. – M. Nejat Aydin Jan 06 '22 at 12:20
  • @M.NejatAydin if you run the script (tested with GNU sed 4.7), you'll see that not escaping the `-` yields a different output than what is expected – Aserre Jan 06 '22 at 13:05
  • @Aserre That's because the string `File-name` has a second match (the line beginning with the `sed`) in the file. This has nothing to do with the range expression. For example, escaping the `i`, as `F\ile-name`, could have resulted in the same output. I don't think this is an appropriate method. See my answer below ( (no escape characters used). – M. Nejat Aydin Jan 06 '22 at 13:15

2 Answers2

0

To illustrate my answer in comments:

$ cat f
    #---------------------------------------------------------------------
    #   File-name: <script1.sh>
    #   Language: bash script
    #   Project: Shell Script Programming Class
    #   Description: xyz
    #   Author: iamgroot
    #---------------------------------------------------------------------

$ sed -n '/File\-name/,/A\uthor/p' f
    #   File-name: <script1.sh>
    #   Language: bash script
    #   Project: Shell Script Programming Class
    #   Description: xyz
    #   Author: iamgroot

$ sed -n '/File-name/,/Author/p' f
    #   File-name: <script1.sh>
    #   Language: bash script
    #   Project: Shell Script Programming Class
    #   Description: xyz
    #   Author: iamgroot
Ivan
  • 6,188
  • 1
  • 16
  • 23
0

The \ before -name is not needed at all, and probably leads to undefined behaviour. It is put there to prevent a second match (for the string File-name) in the sed line, but that is not an appropriate method to do the job. A plausible method could have been:

$ cat testscript

#!/bin/bash

#---------------------------------------------------------------------
#   File-name: <script1.sh>
#   Language: bash script
#   Project: Shell Script Programming Class
#   Description: xyz
#   Author: iamgroot
#---------------------------------------------------------------------
if [ "$1" = '-h' ] ; then
    echo Help:
    sed -n '/^#[[:blank:]]*File-name/,/^#[[:blank:]]*Author/{s/^#//p;}' "$0"
    exit 0
fi

$ ./testscript -h

Help:
   File-name: <script1.sh>
   Language: bash script
   Project: Shell Script Programming Class
   Description: xyz
   Author: iamgroot

However, I'd change the sed line to something like this:

sed -n -e '/^#--*$/!d' -e ':a' -e 'n; /^#--*$/q; s/^#//p; ba' "$0"

This will print out the lines between #--...--s, stripping the leading #s out.

M. Nejat Aydin
  • 9,597
  • 1
  • 7
  • 17
  • `sed -nE '/^#-+$/,/^#-+$/{/^#-+$/d;s/^#//p;}' "$0"` (with GNU or BSD sed) is maybe a bit easier to understand. – Renaud Pacalet Jan 06 '22 at 16:10
  • @RenaudPacalet Surely your version is easier to understand but I don't want to try to match more than one block of lines in the file. My version will quit immediately after printing out the first matching block of lines. – M. Nejat Aydin Jan 07 '22 at 11:26