10
\$\begingroup\$

I'm trying to come up with a script that will add license headers to certain files (depending on extension). My Bash is very average, so any guidance would be much appreciated.

I'm not quite sure what to ask for except for whether I'm making any gross mistakes.

#!/usr/bin/env bash

set -euo pipefail

shopt -s globstar nullglob extglob

lineone="Copyright (c) 2015 Acme Corp, LLC."
linetwo="Unauthorized copying of this file via any medium is strictly prohibited."
linethree="Written by John Doe <j@acme.com>, July 2015" # etc.

printf "// %s
// %s
// %s\n\n" "$lineone" "$linetwo" "$linethree" > "/tmp/$USER-license-go"

printf "{{/*
%s
%s
%s
*/}}\n\n" "$lineone" "$linetwo" "$linethree" > "/tmp/$USER-license-gohtml"

printf "# %s
# %s
# %s\n\n" "$lineone" "$linetwo" "$linethree" > "/tmp/$USER-license-shell"


typ=""
for f in **/*; do
    if [[ -f $f ]]; then
        if ! grep -q Copyright "$f"; then
            case "$f" in
                *.go             ) typ="go"      ;;
                *.gohtml         ) typ="gohtml"  ;;
                @(*.bash|*.conf) ) typ="shell"   ;;
                *                ) continue      ;;
            esac

            cat "/tmp/$USER-license-"$typ "$f" | sponge "$f"
        fi
    fi
done
\$\endgroup\$
  • 2
    \$\begingroup\$ I'll have more to say tomorrow when I'm less tired and less likely to do something stupid with sed, but for now: it kind of bothers me that you don't clean up those tmpfiles. I'd set a trap for them: trap 'rm "/tmp/$USER-license-go" "/tmp/$USER-license-gohtml" "/tmp/$USER-license-shell"' EXIT right after the creation of the third tmpfile \$\endgroup\$ – NightShadeQueen Aug 12 '15 at 4:08
  • 2
    \$\begingroup\$ @NightShadeQueen Please post your suggestion as an answer, even if it is as brief as "You should use trap to ensure that your temp files get cleaned up." \$\endgroup\$ – 200_success Oct 11 '15 at 19:04
5
\$\begingroup\$

This is quite fine. I have a few tips though.

Don't repeat yourself

The base path "/tmp/$USER-license-" appears many times. This is error prone, and it makes it difficult to change later. It would be better to put this in a variable and reuse it everywhere.

here-document instead of printf

Instead of the printf statements to generate the headers, here-documents would be simpler and better, for example:

cat <EOF >"$BASEPATH"-go
// $lineone
// $linetwo
// $linethree

EOF

Tabulation

Aligning things vertically like this may look nice at first:

case "$f" in
    *.go             ) typ="go"      ;;
    *.gohtml         ) typ="gohtml"  ;;
    @(*.bash|*.conf) ) typ="shell"   ;;
    *                ) continue      ;;
esac

The problem with this is if you want to change something later. For example, I don't really see the purpose of the @(...) there, so I would like to simplify:

case "$f" in
    *.go             ) typ="go"      ;;
    *.gohtml         ) typ="gohtml"  ;;
    *.bash|*.conf ) typ="shell"   ;;
    *                ) continue      ;;
esac

But that broke the formatting. What do I do now? Add padding to line up the ) that is now out of line? Or update the other lines? The second option is not great, because I have to change many lines just because I changed one. Just thinking about this is actually a waste of time.

Considering possible future changes, I suggest to avoid this kind of writing style, and stick to good old simple:

case "$f" in
    *.go) typ="go" ;;
    *.gohtml) typ="gohtml" ;;
    *.bash|*.conf) typ="shell" ;;
    *) continue ;;
esac

Alternative to sponge

I didn't know about sponge and moreutils, I'm really glad your has question lead me to discover these gems.

On the other hand, unfortunately sponge is not a standard command, and may not be readily available. Here's an alternative using GNU sed:

license="$BASEPATH"-$typ
sed -i -e "1r$license" -e '1{h;d}' -e '2{x;G}' "$f"
\$\endgroup\$
2
\$\begingroup\$

I may be missing something about this question because my solution seems almost too simple, so I apologize if that is the case ahead of time.


Well, if you have the license in one file (which you should) and then you have the file that you want to copy the license into, couldn't you just adopt a cat?

cat <license> <file> > <file>

Then, all you need to do is loop through each file and run this command.

\$\endgroup\$
  • \$\begingroup\$ I need to insert it at the beginning of each file and each file already contains code :) \$\endgroup\$ – Eric Lagergren Aug 12 '15 at 0:59
  • \$\begingroup\$ @eric_lagergren I understand that. \$\endgroup\$ – SirPython Aug 12 '15 at 1:02
  • \$\begingroup\$ Ok. Unless I misread it your first example would've resulted me in overwriting my file. But yeah cat should work the same as sponge. \$\endgroup\$ – Eric Lagergren Aug 12 '15 at 1:10
  • \$\begingroup\$ Yes, I noticed that it would overwrite. I have fixed it now. \$\endgroup\$ – SirPython Aug 12 '15 at 1:23
  • 2
    \$\begingroup\$ Still not safe; if you're going to do to that, get a sponge from moreutils or use a tempfile. \$\endgroup\$ – NightShadeQueen Aug 12 '15 at 3:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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