
Something about functions in Bash (2017) - okket
http://www.catonmat.net/blog/bash-functions/
======
lsiebert
Just a note that defining a function using the keyword "function" is a
BASHism, not generalizable to every POSIX-compliant shell.

In BASH, as well as any POSIX shell, you can define a function with
function_name () and just remove the "function" from the front.

one of the many things I learned by using Shellcheck for static analysis
[https://github.com/koalaman/shellcheck](https://github.com/koalaman/shellcheck)

~~~
badloginagain
Shellcheck is one of those rare tools that made me a significantly better
developer. In part because the more bash a dev knows the more effective they
are at life in general, in part because it made it easy to follow rigorous
coding standards- allowing me to take the quality-code mindset to less
rigorous environments.

~~~
sethrin
I wrote a short book for novices on shell usage, because it is extremely
important for developers to know. Bash one-liners are usually even pretty
defensible. But I dream about how the world would be if Bash were actually a
good scripting language. It compares favorably to csh, and I fear that's about
the best you can say for it.

~~~
AceJohnny2
> _But I dream about how the world would be if Bash were actually a good
> scripting language. It compares favorably to csh, and I fear that 's about
> the best you can say for it._

I finally started appreciating Perl after having to write some nontrivial Bash
scripts.

(My hierarchy is: default to Bash when my task is mostly running commands. If
there's a bit of text-processing or regex required, Perl. If I need any
hierarchical datastructures, Python)

~~~
ryl00
What's difficult about hierarchial data structures in Perl?

~~~
vgy7ujm
Agreed, it's rather one of Perl's strengths.

------
HerrMonnezza
Nitpick: although the linked page states that defining functions as compund
commands is a `bash` feature, it is actually in the POSIX `sh` standard [1] so
it should work with any POSIX-compliant shell.

[1]:
[http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3...](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_05)

That said, I'm curious what are the nifty tricks that one can do by using
functions as "aliases" for compound commands -- I cannot see much of a
difference between `function sleep1 () { while true; do "$@"; sleep 1; done;
}` and the similar definition without the curly braces. Only once in my life I
have _had_ to use the `function foo () ( ... )` syntax (i.e., using subshell
instead of normal `{ ... }` grouping).

~~~
schoen
I'm always amazed at how many Unix features I assume are GNUisms or bashisms
that turn out to be in POSIX and be much more portable than I've expected!

~~~
webreac
I'm always amazed at how scripts intented to use only POSIX features become
buggy when dash is used instead of bash.

~~~
yjftsjthsd-h
Yeah, for anything that I want to be portable, I explicitly run it with bash,
dash, mksh, and heirloom sh. I figure that if it works in all of those, then
the result is either truly portable... or nobody will ever notice:)

It also should really help that Debian, IIRC, actually sets /bin/sh to dash by
default?

------
maxxxxx
I am always impressed how powerful and efficient shell scripts are but the
syntax is just a killer. Is there a strong reason why all shells have this
crazy syntax? Is it not possible to create a shell with a more expressive
syntax like Java, C# or whatever?

~~~
psetq
Alternatively, Is there any reason today to not just use a language like
Python/Ruby/JS for where shell languages would have been used?

~~~
reificator
Number one reason is availability. Do all of your current and future targets
have the right version of Ruby installed? What if you have a mix of python 2.7
and 3.6?

~~~
sethrin
I'm strongly considering making it a point to do just that: include Ruby in
all the images I can, just to not have to use Bash. For one-liners it's fine,
but I don't get ten lines into a Bash script before missing scripting-language
features. However, if someone were to try to talk me out of what they consider
to be an absurd notion, I would be prepared to take their criticism seriously.

~~~
gkya
I have multiple ~10 line POSIX shell scripts in my dotfiles. I also have a
bunch each of Perl and Python ones [1]. I'd rather not rewrite my shell
scripts with neither of that languages, or Ruby (which I like and use a bit).

When scripting, I find general-purpose languages are better when you have
structured data (i.e. some JSON coming in) or you want to use libraries, and
shell scripting better when you're wiring up multiple programs to work
together, or starting up a program after setting up the environment for it.

IIRC, the FreeBSD sh(1) man page was a good entry to writing POSIX compliant,
thus quite portable shell scripts.

[1] Compare the ones here:
[https://github.com/cadadr/configuration/tree/master/bin](https://github.com/cadadr/configuration/tree/master/bin)

------
llimllib
If you rely on `(` instead of `{` to create a subshell and you don't comment
the heck out of it, you are doing evil

~~~
yjftsjthsd-h
Why? () is the obvious way to get an independent subshell. I guess it's
annoying if you're not used to the distinction, but it's not hard. Is it
really not common knowledge?

~~~
llimllib
Because it parses, visually, EXTREMELY similarly to `{` in a place where
almost everybody who programs in a brace-y language will expect a brace.

Thus most people will not notice it unless you point it out very explicitly,
and it has the potential to cause great confusion.

------
inetknght
If you get bored with basic shell commands, I highly recommend learning what
GNU coreutils provide. I never would have loved Linux without this installed.

[https://www.gnu.org/software/coreutils/manual/html_node/inde...](https://www.gnu.org/software/coreutils/manual/html_node/index.html)

------
derekp7
Something else you can do with BASH functions is use:

    
    
        declare -f function_name
    

to print out the contents of a function, in a format that can be directly
evaluated with command substitution. This is useful if you want to send a
function (or a number of functions) into another BASH instance (such as via an
SSH connection).

A google search for "RPC in Bash" will take you to a GIST I put up on Github a
while back that gives details of how this works.

You can do this in ksh93 also, I believe you use typeset -f instead of declare
-f.

~~~
jodrellblank
You can do this in PowerShell also:

    
    
        get-content function:function_name
    

`function:` being a filesystem-like PS Provider.

------
pas
> Not only do these tricks make your code nicer [...]

Huh.

~~~
zzzeek
for context, author of blog post has written two published Perl books. To make
matters worse, they are called "Perl One Liners", "Perl One Liners Explained".

~~~
bewuethr
To clarify: "Perl One-Liners Explained" is self-published, and "Perl One-
Liners" is based on it and published by No Starch Press. Not sure why that
makes "matters worse"?

He also self-published "Awk One-Liners Explained" and "Sed One-Liners
Explained" and has a "Bash One-Liners Explained" in the pipeline, see
[http://www.catonmat.net/books](http://www.catonmat.net/books)

------
redcat255
This seems like a good place to ask. I've been putting off properly learning
bash (instead of googling for basic structures whenever I need to write a
script) for quite a while now, what resources do you recommend for doing so?

------
KeyboardFire
Hmm, why doesn't `fn() echo test; fn` work? It seems to work in zsh, but not
bash.

~~~
HerrMonnezza
Because `echo test` is not a compound command.

Informally, a compound command is a list of commands (`( ... )` or `{ ... }`)
or a looping or conditional construct. See [1] for a precise definition.

[1]:
[https://tiswww.case.edu/php/chet/bash/bashref.html#Compound-...](https://tiswww.case.edu/php/chet/bash/bashref.html#Compound-
Commands)

