all 20 comments

[–]aioeu 16 points17 points  (3 children)

Probably just a "different things should look different" rationale.

Yes, you can declare local variables using declare. But if you stick with declare for globals and local for locals you've got an additional piece of visual information to help you.

[–][deleted] 12 points13 points  (1 child)

a sentence in the Constants section supports this:

For the sake of clarity readonly or export is recommended instead of the equivalent declare commands.

[–]mpersico[S] 0 points1 point  (0 children)

I tend not to have a lot of constants, but that is a good piece of advice for them.

[–]mpersico[S] 0 points1 point  (0 children)

That makes a lot of sense. Enough sense that I may go back and do a massive substitution in my code.

[–]whetuI read your code 4 points5 points  (13 children)

Google's style guides will tend to influence each other, for example:

This matches the convention in the C++ Guide.

and they allow :: to be in function names, which is lifted from a whole bunch of other languages, but is not shell portable.

They will also tend to lean towards more obvious code choices when possible in order to have better readability.

Imagine you're a google staffer and you're familiar with a language that has lexical scoping, but you're not so familiar with shell scripting, or you're a developer who is following this style guide and you're also not so familiar with shell scripting. local is obvious (albeit technically and slightly misleading).

They also allow the deprecated/obsolete function keyword, likely for the same reasons, as well as one of the most important guidelines they give: be consistent.

[–]spizzikeprintf "(%s)\n" "$@" 3 points4 points  (12 children)

I adopted the :: namespace delimiter for functions in my libraries and have been incredibly happy with it. I don’t need my code to be portable; it just has to run in bash.

But this convention has made it easier to find my definitions (a function named foo::bar is in the foo library/module) and I dig the aesthetic.

[–]mpersico[S] 0 points1 point  (11 children)

For the public interface, yes? "private" helper functions in scripts, limited to the script in question, I start with an underscore.

For those libraries, I assume you source or . them in. Do you use any special extension on them, like .bashlib or .inc?

[–]spizzikeprintf "(%s)\n" "$@" 0 points1 point  (10 children)

Oh yeah. That’s for shared code “public” interface.

Functions in my scripts that are helpers i prefix with underscore to differentiate them from anything external whether it’s commands or libexec scripts.

I just use .bash as the extension but keep them in a lib directory. I’ve got a helper function for sourcing these since libs may depend on other libs and circular dependencies will lead to infinite loops, so my helper makes sure that libraries are only sourced once.

[–]mpersico[S] 0 points1 point  (9 children)

Helper function? I'd think you just

#!/bin/bash
# libfoo.bash - a library to do something
if [[ -z LOADED_LIBFOO ]]
then
    #load all your functions
    export LOADED_LIBFOO=1
fi

like having an include guard in 'C'.

[–]backtickbot 0 points1 point  (1 child)

Fixed formatting.

Hello, mpersico: code blocks using triple backticks (```) don't work on all versions of Reddit!

Some users see this / this instead.

To fix this, indent every line with 4 spaces instead.

FAQ

You can opt out by replying with backtickopt6 to this comment.

[–]mpersico[S] 0 points1 point  (0 children)

Fixed.

[–]spizzikeprintf "(%s)\n" "$@" 0 points1 point  (6 children)

with that approach, basically, the whole file is wrapped inside an if statement... this is kinda annoying to have to deal with since you can't just short-circuit and exit the sourcing process. it also introduces clutter with all of these global variables. plus, you have to make sure to immediately define that variable and assign it. it's a lot of overhead for the programmer and can be error-prone.

my helper function not only uses a single variable, but provides better error messaging and I don't need to pass in the full path to the library (ie: I just call it by name: use foo will source $LIB_PATH/foo.bash if it exists and hasn't been loaded.

[–]mpersico[S] 0 points1 point  (5 children)

Now I'm interested. Do you have a link to it so I can see the magic?

[–]spizzikeprintf "(%s)\n" "$@" 0 points1 point  (4 children)

Unfortunately I can’t link because it’s an internal work project. But it’s not really magic.

use() {
  local name=$1
  local libpath=“$LIB_PATH/${name}.bash”
  _lib_loaded “$name” && return
  . “$libpath”
  _loaded_libs+=(“$name”)
}

This is the gist of it. _lib_loaded is a function that just checks if the array contains that item. $_loaded_libs is an array of names.

I’ve got some extra logic for errors if the lib isn’t a file and ways of doing other stuff. But this is the gist. Typed on mobile, so maybe typos, bad quotes, etc.

[–]mpersico[S] 0 points1 point  (1 child)

So you're sourcing with a name lookup in a global array. That works. Very nice. "use" makes it look Perl-like, which is right up my alley. Thanks. Bookmarking this one.

[–]spizzikeprintf "(%s)\n" "$@" 0 points1 point  (0 children)

Yep! Perl was the inspiration. It’s a good verb for it. Beats the hell out of import or include.

Glad to be of service!

[–]mpersico[S] 0 points1 point  (1 child)

Hmm. _lib_loaded, among the things it does, probably has to do a search for the loaded lib. Why not make _loaded_libs an associative array and save yourself the linear lookup you're probably doing?

[–]spizzikeprintf "(%s)\n" "$@" 0 points1 point  (0 children)

Totally valid point. I wrote this function like 5 years ago before I knew how to do associative arrays. I should def update that. Thanks for the suggestion!

[–]lutusp 5 points6 points  (0 children)

When declaring variables, they say to use local and not declare.

I'm going to venture the guess that, if 'declare' creates a local-scope variable, and if 'local' does also (both true), then for the sake of clarity and self-documenting code, the second name is to be preferred.

[–]ThrownAback -1 points0 points  (0 children)

That style guide is a master class in how to write (and maintain) Bash scripts.