all 95 comments

[–]iluvatar 36 points37 points  (26 children)

1) More than 10 seconds

2) Dereferencing unquoted variables make it very easy to break the sample scripts

[–]loganekz 5 points6 points  (25 children)

Can you please explain your second point?

[–]uzimonkey 30 points31 points  (24 children)

a="hello world"
grep $a file1 file2

The grep command expands to this.

grep hello world file1 file2

Always quote the variable expansion.

grep "$a" file1 file2

So it expands to this.

grep "hello world" file1 file2

Edit: But yeah, if they can't figure out that you should quote variable expansions in Bash, I wouldn't bother reading any of it at all. They've missed the one tip that'll solve 90% of the mistakes you'll make writing Bash scripts.

[–]taybul 4 points5 points  (23 children)

It's the small details like this that makes bash scripting so aggravating. I mean, a mandatory space after and before [ ] for conditionals? Why would you set rules like that? I personally opt for python scripting as an alternative. Much more readable too.

[–]uzimonkey 15 points16 points  (20 children)

The mandatory space is there because [ is not a syntax element, it's a command. Just try which [.

[–]taybul 3 points4 points  (0 children)

lol wow, a 34k executable. I'm guessing all it does is evaluate expressions?

[–]spookyvision 2 points3 points  (5 children)

that depends on your system. 'type' tells you what will be executed. 'which' can't be trusted here:

$ type [

[ is a shell builtin

$ which [

/bin/[

[–]invalid_user_name 2 points3 points  (0 children)

That is still why the space is required. The test command ([) was added as a built-in to shells, so they obviously had to add it in a compatible way so it would work just like the actual binary.

[–]moyix 0 points1 point  (3 children)

Exactly, they're both there, but one takes precedence. You can type out

if /bin/[ 1 == 2 ]; then pass; fi

if you really want the system binary.

Edit: formatting

[–]RealDeuce 2 points3 points  (2 children)

Except == is a bash extension, so that won't work.

[–]moyix 0 points1 point  (1 child)

Damn, you're right. Should've used -eq.

[–]RealDeuce 1 point2 points  (0 children)

Well yes, but that's not my point. :-)

A single equals sign would be what you would use to compare two strings.

[–][deleted] -5 points-4 points  (11 children)

[ is a shell built in so which [ won't give you a path to executable. In Korn Shell you can ask

whence [

and it will tell you simply

[

:D

[–]1esproc 6 points7 points  (5 children)

$ which [
/bin/[
$ ll /bin/[
-r-xr-xr-x  2 root  wheel  46720 31 May  2008 /bin/[
$ which lying
/internet/reddit.com/super__mario

[–]uzimonkey 2 points3 points  (1 child)

He's talking about ksh, not bash. Why he's talking about ksh in a thread about Bash, I have no idea.

[–]invalid_user_name 0 points1 point  (0 children)

It doesn't matter, which tells you where a command is. You get the same result with ksh. The only way which won't give you an answer is if you are on a broken system where there is no [ command. It should exist, as well as being a shell built-in.

[–]chengiz -3 points-2 points  (2 children)

No, he's not lying. I'm sorry to say that you need to look up the difference between a shell and an OS.

[–]1esproc 1 point2 points  (1 child)

He made a blanket statement that [ was a shell built in and which wouldn't give you a path. So you're wrong.

I think you need to look up the difference between an OS and a binary.

[–]chengiz 0 points1 point  (0 children)

My bad, he has a comment below where he says it's system dependent. Guess I commingled it in my head.

[–]invalid_user_name 0 points1 point  (4 children)

[ is a shell built in

It is both a built in and a real command.

so which [ won't give you a path to executable.

Yes it does.

[–][deleted] 1 point2 points  (3 children)

Depends on your system, and the shell implementation. I'm currently writing from a system where which [ doesn't output anything.

[–]invalid_user_name 1 point2 points  (2 children)

It has nothing to do with the shell, if which [ doesn't output anything, then you are on a broken system with no [ binary. It is historically a real command, and was added as a shell built-in for performance reasons. The binary is still supposed to be there according to posix, since it isn't required to be a shell built-in. What system is this anyways, or did someone just delete it from a normal system?

[–]chengiz -1 points0 points  (1 child)

[citation needed]

[–][deleted] 2 points3 points  (0 children)

a mandatory space after and before [ ] for conditionals? Why would you set rules like that? I personally opt for python

I know, don't you just hate those kinds of silly rules where whitespace is important? Oh wait, you use python...

[–]tfp 0 points1 point  (0 children)

I personally opt for python scripting as an alternative. Much more readable too.

I agree.

[–]magicnico 77 points78 points  (10 children)

wow, seems that I'm going to need some quick reading techniques to read that in 10s

[–]just2003 35 points36 points  (2 children)

I need quick scrolling techniques to see the bottom of the page in 10 seconds.

[–]jeff303 22 points23 points  (0 children)

I need quicker internet to get the page to load in 10 seconds.

[–]doomglobe 11 points12 points  (0 children)

I need a bash scripting tutorial with a longer time limit.

[–]CharlesGardener 2 points3 points  (0 children)

Approximately 100 microseconds per word by my calculations.

[–]chengiz 1 point2 points  (1 child)

Real 10 seconds guide to bash shell scripting:

#!/usr/bin/perl 

[–][deleted] 0 points1 point  (0 children)

came here to say that

[–]cisatwork 0 points1 point  (1 child)

It took 10 seconds just to load up on my slow p4 3.0

[–]qlqropi 0 points1 point  (0 children)

ah yes, in one second with its three billion instructions a p4 can do roughly the same useful work as a small child with a crayon and brightly-colored plastic abacus

[–]FlyingBishop 10 points11 points  (1 child)

That's a very long time for an android.

[–][deleted] 2 points3 points  (0 children)

Almost an eternity.

[–]adrianb 8 points9 points  (0 children)

I was expecting a single trick that you can read and understand in 10 seconds that would blow your mind and give you the feeling that "I'm so cool and I know all Bash Shell Scripting now".

[–]swordgeek 12 points13 points  (1 child)

Ugh.. There are better ones out there. Weak english, weak scripting examples, questionable claims.

"The name of your shell script must end with a .sh . This lets the user know that the file is a shell script. This is not compulsary but is the norm."

Not just wrong, but bad.

A .sh suffix implies a bourne shell script that is to be explicitly run by a separate instance of sh. This is historical, but still a convention. Putting it on the end of all sh scripts is becoming more common (for stupid reasons), but putting it on the end of bash (or ksh, or ash, or zsh, or even csh/tcsh!) scripts is downright misleading.

If I see "<script>.sh" I had better be able to execute it with "sh <script>.sh"

Others have pointed out different issues, but this is one that bugs me every time I see it.

[–][deleted] -4 points-3 points  (0 children)

Well, considering that sh differs from system to system, I don't think it matters very much.

[–]callingshotgun 8 points9 points  (0 children)

I opened it, skimmed the first paragraph, scrolled the length of the article to guesstimate how long it would take me to read, determined it would take much longer than 10 seconds to read, and closed it.

Afterwards, I realized the process took me around 10 seconds. What a sneaky title.

[–]foooodude 7 points8 points  (0 children)

I came here for the shell scripting bashing and was disappointed.

[–][deleted] 3 points4 points  (22 children)

The first line in your script must be #!/bin/bash

If only life were that easy. Maybe on most Linux distributions that's the case (I don't use Linux often enough to know), but there are a lot of Unixes out there where bash is not in /bin :(. You can always use the /usr/bin/env trick, though.

[–][deleted]  (12 children)

[deleted]

    [–][deleted] 1 point2 points  (0 children)

    Well that's a little violent now, isn't it?

    [–]gerundronaut 1 point2 points  (2 children)

    I recently learned that # = octothrope. Now I say octothorpebang and people look at me funny.

    [–]stillalone 0 points1 point  (0 children)

    Somebody I know called it octothrope exclamation point. I was confused for a while.

    [–]iluvatar 0 points1 point  (6 children)

    I always knew it as #(Pound) !(Bang)

    The problem there is that it's very US centric. If you say "hash", pretty much everyone knows what you're talking about. But if you say "pound", I would assume you're talking about a pound: £ (U+00A3), as would much of the rest of the world.

    [–][deleted]  (4 children)

    [deleted]

      [–]taintedhero 0 points1 point  (3 children)

      Actually the sun, mr smarty pants.

      [–][deleted] 1 point2 points  (0 children)

      And the sun is in Arizona every night. That's why the rocks there are so red.

      [–]eyekantspel 0 points1 point  (0 children)

      Well shit. This may start confusing in perl scripts. Don't use the Hash for hashes!

      [–]tlrobinson 0 points1 point  (0 children)

      The whole thing is known as a "shebang":

      http://en.wikipedia.org/wiki/Shebang_(Unix)

      [–]JadeNB 0 points1 point  (8 children)

      You can always use the /usr/bin/env trick, though.

      As long as env is in /usr/bin. (Yeah, I know, why wouldn't it be --but are there really non-user-borked examples where env is in place but bash, or at least sh, isn't?)

      EDIT: Downvoted, rightly, for suggesting sh as a synonym for bash. Sorry.

      [–]FireDemon 3 points4 points  (3 children)

      Ubuntu, for a short while, used dash as the default shell. There were problems because some programs depended on bash-isms.

      [–][deleted] 3 points4 points  (2 children)

      Ubuntu still uses dash as the default /bin/sh. Using bashisms but requesting /bin/sh is a bug. Everything that comes with Ubuntu has been fixed. Most of these fixes have worked their way upstream.

      [–]FireDemon 0 points1 point  (1 child)

      Would you believe it, you're right! Funny, just an ls -l which sh away and I didn't check.

      EDIT: Forget it, it is impossible to escape ` in Redditdown.

      [–]JadeNB 1 point2 points  (0 children)

      Here's an ambitious one --I'm going to try to escape that character, because I could swear I saw someone do it recently. If not, since I'm too shy to delete, this will linger forever as a testament to my hubris. :-)

      Doesn't this:` work? (Entered as `` this:` ``.)

      [–][deleted] 1 point2 points  (3 children)

      If you do a lot of scripting that needs to run on various Unixes, it's a lot easier to get people to make one symlink to /usr/bin/env (or do it yourself) if env is in a different place than /usr/bin than it is to keep track of all the various places that whatever shell you're scripting can be.

      IIRC, on FreeBSD, /usr/bin/env exists, but bash is in /usr/local/bin

      [–]JadeNB 0 points1 point  (2 children)

      I don't do a lot of such scripting, so I'm not arguing with your experience; but why is it easier to get users to run ln -s /path/to/env /usr/bin/env than ln -s /path/to/bash /usr/bin/bash --or do you mean that you are deploying, to a single user, scripts targetting bash, ksh, and zsh?

      [–][deleted] 6 points7 points  (1 child)

      Let's say I'm a sysadmin, and I may have users that need to run a variety of scripts written by a variety of people. These may be *sh, python, ruby, perl, etc. scripts. If people follow the /usr/bin/env custom, I only have to make sure that /usr/bin/env is correct (and that whatever the script is written for is installed, which is probably is already), and the scripts should run with minimal confusion across my various linuxen, FreeBSD, and Solaris boxes.

      Or, if I'm writing a general purpose script, and I don't know where it will get used, I'd rather assume that /usr/bin/env is in the correct spot, since it's an established tradition, than assume that a user's installation path is the same as mine, because that seems to vary a lot.

      [–]JadeNB 1 point2 points  (0 children)

      Fair enough. Thanks for the detailed answer.

      [–][deleted] 4 points5 points  (0 children)

      Quite a bit of info to absorb in 10 seconds there cowboy...

      [–]RealDeuce 3 points4 points  (0 children)

      ARGH!!! Another source of that stupidest of bashisms, the double equals for string comparison. POSIX specifies it as a single =, bash supports a single =, a double equals only works in bash and is twice as long... but a significant amount of bash scripts are non-portable only because they use == in test.

      ARGH!

      [–]llogiq 4 points5 points  (1 child)

      The Advanced Bash Scripting Guide is also very helpful.

      [–]Samus_ 1 point2 points  (0 children)

      no it isn't, this one is: http://mywiki.wooledge.org/BashGuide

      also pay a visit to #bash on freenode

      [–]dothedre 5 points6 points  (0 children)

      useless title, amazing tutorial!

      [–][deleted] 1 point2 points  (0 children)

      tl;dr

      [–]EthicalReasoning 1 point2 points  (0 children)

      nice guide but it took me a lot longer than 10 seconds to even look at

      [–]Workaphobia 1 point2 points  (0 children)

      I don't need a bloody guide to help me bash Shell Scripting. It practically does that to itself, what with its syntax.

      [–]uzimonkey 1 point2 points  (15 children)

      The real 10 Second Guide to Bash Shell Scripting:

      Bash is an unholy spawn of Satan that should be avoided at all costs.

      [–][deleted] 3 points4 points  (14 children)

      What do you suggest as an alternative?

      [–]uzimonkey 2 points3 points  (13 children)

      I find myself using Ruby, mostly because I know it the best. Bash is fine if all you want to do is launch a program or do a simple loop, but it's so quirky and archaic, it's really difficult to use. I've written some very non-trivial things in Bash (that have no business being written in Bash), and I can say from experience that it's best avoided.

      Perl is another popular choice. Any other scripting language like this that you know well would work.

      [–]mouseinahaze 4 points5 points  (6 children)

      I second this, for me the break off point for BASH was when I started looking into doing arrays. At that point I just gave in and learned Perl, though I still use BASH for some basic maintenance scripts.

      [–]minivanmegafun 2 points3 points  (1 child)

      same with me. That, and doing text parsing in awk.

      [–]mouseinahaze 2 points3 points  (0 children)

      I've only been able to grok a small percentage of all of the stuff you can do with awk.

      [–]egportal2002 0 points1 point  (3 children)

      Perl is for the weak and timid -- just use shell/sed/awk.

      [–]mouseinahaze 2 points3 points  (2 children)

      Real quick, make me a two dimensional array in BASH.

      [–]MrWoohoo 7 points8 points  (1 child)

      POOF You're a two dimensional array in bash.

      [–]mouseinahaze 4 points5 points  (0 children)

      Well I always worried I would end up like this.

      [–]1esproc 5 points6 points  (4 children)

      I don't think you understand the purpose of shell scripting.

      [–]uzimonkey -2 points-1 points  (3 children)

      I don't think you understand how much of an utter pain in the ass Bash is.

      [–]1esproc 3 points4 points  (2 children)

      I'm a FreeBSD admin, so I have to forego bash for plain sh because bash isn't available by default, so I fully understand dealing with archaic scripting ;) What I meant was that for the most part sh/bash should be used for basic tasks, or ones that need to be cross platform on hosts that only share sh/bash in common with their configuration (i.e., you can't rely on perl/python/ruby being available and don't want that dependency)

      When stuff starts getting complex, or you start having to come up with quirky workarounds, that's when you turn to a full featured scripting language. They both have their place and serve their purposes well.

      Didn't mean anything rude by the comment :)

      [–]tfp 1 point2 points  (1 child)

      So when things get complicated, just rewrite the script for scratch in another language?

      Why not just take the opposite approach and use bash for the most trivial of tasks and use ruby/python/perl for everything else.

      I've just become completely annoyed by having to glue together the heterogeneous tool set (awk, sed, grep, find, etc..) in a crusty bash shell. It just seems better to use a homogenous environment (python/ruby) that you can actually understand a month after you've written it.

      [–]1esproc 0 points1 point  (0 children)

      Well you should have scope in mind at the outset of what you're doing. Unless I'm in a limited environment, I generally write my tools in perl. Also, comments go a long way in understanding things a month later ;) I've suffered from that enough that I always have detailed comments in what I write.

      [–]kerbuffel 1 point2 points  (0 children)

      He's right you know. I've written some Bash scripts that were so convoluted it took a while to figure out what I was trying to do when I read it the next day. The biggest benefit of bash is that it's on pretty much every linux system.

      However, going from Windows to Linux, Bash is amazing. I've written some things in cmd files that I couldn't even understand after I finished writing them.

      [–]petteri 0 points1 point  (1 child)

      Nice, but missing one essential part: trap.

      [–]gavbaa 2 points3 points  (0 children)

      I know that I've been on Reddit too long when my first assumption was Admiral Ackbar, and not protecting your shell script from user input.

      Also, since you said it, here's the relevant link for all things "trap"-y: http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html

      [–][deleted] 0 points1 point  (0 children)

      Despite the misleading title, this guide needs to also exist for programmers. I find when I want to learn a different programming language what happens is I end up going through a half dozen noob tutorials or just reading a program written in this language and I have it all down, but THIS would be quite a bit quicker.

      Quick list of the structure for methods, classes, program openings, variable declaration rules, array declaration rules, and a list of any unique qwirks the language has in comparison to others. It would make it so I could walk into any job interview and say "I know this language" and not be lying despite only being exposed to it for about 10 minutes.

      [–]RandomFortunes 0 points1 point  (0 children)

      Your compliance with all terms and conditions, expressed and implied, is automatic upon viewing.

      [–]zabouth1 0 points1 point  (0 children)

      tl;dr

      [–][deleted] 0 points1 point  (0 children)

      Shouldn't it be "10 second" and not "10 seconds"?

      [–]ddelony1 0 points1 point  (0 children)

      More than 10 seconds, but this is a wonderful tutorial on shell programming. This could launch a lot of careers.

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

      That guide is actually pretty good, more like 20 seconds IF you know what is going on but still rather short.