Email or username:

Password:

Forgot your password?
Nathan Manceaux-Panot

Just discovered in amazement that in Bash scripts, any variable named `SECONDS` will automatically increment every second. Bash is bonkers

43 comments
Nicolas :eisfunke_logo:

@Cykelero didn't want to believe you, so I tried it and now I'm staring at my screen in disbelief

#!/usr/bin/env bash

SECONDS=3

for i in $(seq 1 10); do
echo $SECONDS
sleep 1
done

yields

$ ./ohno.sh
3
4
5
6
7
8
9
10
11
12
Steven Reed

@eisfunke @Cykelero one of the few pleasures of getting old is watching people significantly younger than me being weirded out by this sort of thing for the first time :)

Heals :heart_nb: (comms open)

@eisfunke @Cykelero @jakehamilton the actual use of the variable is to count the number of seconds since the bash instance was started - you don't have to assign anything to it but assigning a value resets it to that value (and it normally only works with the uppercase SECONDS).

Bash also offers $RANDOM (you can guess what it does) as well as $EPOCHSECONDS and $EPOCHREALTIME for the more exotic ones.

And.. many more (gnu.org/software/bash/manual/b)

David Cantrell 🏏

@Cykelero it took me ages to track down that bug in one of my scripts a few months back. And when I say "track down" I mean "ineffectually whine for hours WHY DO YOU HATE ME? WHY IS THE COMPUTER DOING RANDOM STUPID SHIT?" until I asked someone on the internet and got an answer within approximately six seconds. Or was it seven? eight? nine? ...

Nathan Manceaux-Panot

@DrHyde Exactly!! Their intent was good, but the implementation deeply unfortunate

Nik | Klampfradler 🎸🚲

@DrHyde @Cykelero

Huh… that's a pre-defined variable counting the runtime of the script. The core issue here is that you used a reserved variable. There is exactly one variable named SECONDS, so "bash incrementing any variable named SECONDS" doesn't make much sense.

tldp.org/LDP/abs/html/internal

Nathan Manceaux-Panot

@nik Right! That’s the technically-accurate explanation. But I think many people will write a script *thinking* they’re just creating a regular old variable, not realizing they’re stepping on a landmine of good intentions

chebra

@Cykelero The same could happen with any variable if it conflicts with a global variable. If you use variable USER, you might also not realize that it already contains a value. And the value of PWD also sometimes changes "unexpectedly".

Carl

@DrHyde Why would you do 5,6,7,8... SECONDS RTFM if you could spent hours of whining and debugging instead?! That does not seem right. @Cykelero

David Cantrell 🏏

@carl @Cykelero no normal person would expect the name of a variable to have special meaning and so think to RTFM and see if the variable name had a special meaning.

Nathan Manceaux-Panot

@carl @DrHyde pls no being mean in my mentions mister

Andrew Reid

@Cykelero
Holy crap.

If I randomly do "echo $SECONDS", it seems to start at the number of seconds since the shell was launched.

It does not show up in "env | grep SECONDS".

Bonkers, like the man said.

Paul Johnson 🎶

@Cykelero Zsh too, and in zsh it can be floating point, if you want.

Another reason to prefer lowercase for your local $variables

Daniel Terhorst-North

@Cykelero you are just referencing a magic variable called SECONDS built into bash (and zsh). There are a few others that do ‘interesting’ things too!

Grumpy Old Techie 🕊️

@tastapod @Cykelero /bin/sh on FreeBSD doesn’t do that. If we can believe the man page that version of the Bourne shell is with us since 1989

/bin/sh
$ SECONDS=3
$
$ for i in $(seq 1 10); do
> echo $SECONDS
> sleep 1
> done
3
3
3
3
3
3
3
3
3
3

Daniel Terhorst-North

@grumpyoldtechie @Cykelero yep, it’s a bash-ism. Nothing to do with posix Bourne shell. Not sure about ksh.

Daniel Terhorst-North

@grumpyoldtechie @Cykelero looks like ksh also has SECONDS but theirs is more sensible, which is generally true of ksh vs bash in my experience:

unix.stackexchange.com/a/11499

Elliot Shank

@Cykelero Have you ever looked at /dev/tcp/… and /dev/udp/… ? Non-existent "files" that allow you to do networking from Bash.

mtp

@Cykelero This was a good nerd snipe. Here I was convinced that this was yet more insanity that accreted into Bash (alone) over the years, but nope: parsimonious ksh and mksh have it, too!

Tobias

@Cykelero Just checked, true for `zsh` and `ksh`, too.
The latter even gives you fractional parts up to the millisecond…

xenos 🐧🔰🇵🇭

@Cykelero did you check the man page for bash? it's documented there under shell variables.

Ellie

@Cykelero how many variables named `SECONDS` can exist concurrently?

mirabilos

@Cykelero by the way, you should not define a variable in your script that’s comprised solely of uppercase letters, digits and underscore: these may be reserved by the implementation.

Environment variable names used by the utilities in the Shell and Utilities volume of POSIX.1-2024 consist solely of uppercase letters, digits, and the ('_') from the characters defined in [4]Portable Character Set and do not begin with a digit. Other characters, and byte sequences that do not form valid characters, may be permitted by an implementation; applications shall tolerate the presence of such names. Uppercase and lowercase letters shall retain their unique identities and shall not be folded together. The name space of environment variable names containing lowercase letters is reserved for applications. Applications can define any environment variables with names from this name space without modifying the behavior of the standard utilities.

(A separate location in POSIX makes this logic mostly apply to shell variables.)

So, user variables in shell scripts should always be lowercase.

@Cykelero by the way, you should not define a variable in your script that’s comprised solely of uppercase letters, digits and underscore: these may be reserved by the implementation.

Environment variable names used by the utilities in the Shell and Utilities volume of POSIX.1-2024 consist solely of uppercase letters, digits, and the ('_') from the characters defined in [4]Portable Character Set and do not begin with a digit. Other characters, and byte sequences that do not form valid characters,...

ferricoxide

@Cykelero@mas.to

Primarily working on RHEL-based (and derivative) systems, a lot of the nifty BASHisms tend to be missing because the version of BASH is typically five or more years behind current.

#Linux

Go Up